您好,欢迎进入爱游戏APP下载有限公司官网!

咨询热线:

400-888-8888

爱游戏APP首页-专门画了9张图,搞懂设计模式6大原则,这次应该可以了吧

发布时间:2021-12-15人气:
本文摘要:前言设计模式(Design pattern)是一套被重复使用、多数人知晓的、经由分类编目的、代码设计履历的总结。使用设计模式是为了可重用代码、让代码更容易被他人明白、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码体例真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

爱游戏APP首页

前言设计模式(Design pattern)是一套被重复使用、多数人知晓的、经由分类编目的、代码设计履历的总结。使用设计模式是为了可重用代码、让代码更容易被他人明白、保证代码可靠性。

毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码体例真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。借用并改编一下鲁迅老师《家乡》中的一句话,一句话归纳综合设计模式: 希望本无所谓有,无所谓无.这正如coding的设计模式,其实coding本没有设计模式,用的人多了,也便成了设计模式读者福利:关注小编+私信回复【项目】获取整理好的100+个Java项目视频+源码+条记设计模式的六大原则:1.开闭原则(Open Closed Principle,OCP)2.里氏代换原则(Liskov Substitution Principle,LSP)3.依赖倒转原则(Dependency Inversion Principle,DIP)4.接口隔离原则(Interface Segregation Principle,ISP)5.合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)6.最小知识原则(Principle of Least Knowledge,PLK,也叫迪米特规则)开闭原则具有理想主义的色彩,它是面向工具设计的终极目的。

其他几条,则可以看做是开闭原则的实现方法。设计模式就是实现了这些原则,从而到达了代码复用、增加可维护性的目的。

开闭原则1.观点: 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。模块应只管在不修改原(是“原”,指原来的代码)代码的情况下举行扩展。2.模拟场景: 在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码举行修改时,可能会给旧代码中引入错误,也可能会使我们不得差池整个功效举行重构,而且需要原有代码经由重新测试。

3.Solution: 当软件需要变化时,只管通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。4.注意事项: 通过接口或者抽象类约束扩展,对扩展举行界限限定,不允许泛起在接口或抽象类中不存在的public方法参数类型、引用工具只管使用接口或者抽象类,而不是实现类抽象层只管保持稳定,一旦确定即不允许修改5.开闭原则的优点: 可复用性可维护性6.开闭原则图解:里氏代换原则1.概述: 派生类(子类)工具能够替换其基类(父类)工具被挪用2.观点: 里氏代换原则(Liskov Substitution Principle LSP)面向工具设计的基本原则之一。

里氏代换原则中说,任何基类可以泛起的地方,子类一定可以泛起。LSP是继续复用的基石,只有当衍生类可以替换掉基类,软件单元的功效不受到影响时,基类才气真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的增补。

实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继续关系就是抽象化的详细实现,所以里氏代换原则是对实现抽象化的详细步骤的规范。

(源自百度百科)3.子类为什么可以替换父类的位置?: 当满足继续的时候,父类肯定存在非私有成员,子类肯定是获得了父类的这些非私有成员(假设,父类的的成员全部是私有的,那么子类没措施从父类继续任何成员,也就不存在继续的观点了)。既然子类继续了父类的这些非私有成员,那么父类工具也就可以在子类工具中挪用这些非私有成员。

所以,子类工具可以替换父类工具的位置。4.里氏代换原则优点: 需求变化时,只须继续,而此外工具不会改变。由于里氏代换原则才使得开放关闭成为可能。

这样使得子类在父类无需修改的话就可以扩展。5.里氏代换原则Demo: 代码正文://------------------------------------------------------------------------------// <copyright file="Program.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestApp{ using System; class Program { static void Main(string[] args) { Transportation transportation = new Transportation(); transportation.Say(); Transportation sedan = new Sedan(); sedan.Say(); Console.ReadKey(); } } class Transportation { public Transportation() { Console.WriteLine("Transportation?"); } public virtual void Say() { Console.WriteLine("121"); } } class Sedan:Transportation { public Sedan() { Console.WriteLine("Transportation:Sedan"); } public override void Say() { Console.WriteLine("Sedan"); } } class Bicycles : Transportation { public Bicycles() { Console.WriteLine("Transportation:Bicycles"); } public override void Say() { Console.WriteLine("Bicycles"); } }}代码效果:6.里氏代换原则图解:依赖倒转原则1.观点: 依赖倒置原则(Dependence Inversion Principle)是法式要依赖于抽象接口,不要依赖于详细实现。简朴的说就是要求对抽象举行编程,不要对实现举行编程,这样就降低了客户与实现模块间的耦合。2.依赖倒转原则用处: 有些时候为了代码复用,一般会把常用的代码写成函数或类库。

这样开发新项目时,直接用就行了。好比做项目时大多要会见数据库,所以我们就把会见数据库的代码写成了函数。

每次做项目去挪用这些函数。那么我们的问题来了。我们要做新项目时,发现业务逻辑的高层模块都是一样的,但客户却希望使用差别的数据库或存储住处方式,这时就泛起贫苦了。我们希望能再次使用这些高层模块,但高层模块都是与低层的会见数据库绑定在一起,没措施复用这些高层模块。

所以不管是高层模块和低层模块都应该依赖于抽象,详细一点就是接口或抽象类,只要接口是稳定的,那么任何一个更改都不用担忧了。3.注意事项: 高层模块不应该依赖低层模块。

两个都应该依赖抽象。抽象不应该依赖细节。细节应该依赖抽象。

4.模拟场景: 场景:假设现在需要一个Monitor工具,去运行一些已有的APP,自动化来完成我们的事情。Monitor工具需要启动这些已有的APP,而且写下Log。代码实现1://------------------------------------------------------------------------------// <copyright file="Dependency.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestLibrary.ExtensionsClass{ using System; public class AppOne { public bool Start() { Console.WriteLine("1号APP开始启动"); return true; } public bool ExportLog() { Console.WriteLine("1号APP输出日志"); return true; } } public class AppTwo { public bool Start() { Console.WriteLine("2号APP开始启动"); return true; } public bool ExportLog() { Console.WriteLine("2号APP输出日志"); return true; } } public class Monitor { public enum AppNumber { AppOne=1, AppTwo=2 } private AppOne appOne = new AppOne(); private AppTwo appTwo = new AppTwo(); private AppNumber number; public Monitor(AppNumber number) { this.number = number; } public bool StartApp() { return number == AppNumber.AppOne ? appOne.Start() : appTwo.Start(); } public bool ExportAppLog() { return number == AppNumber.AppOne ? appOne.ExportLog() : appTwo.ExportLog(); } }}代码剖析1:在代码实现1中我们已经轻松实现了Monitor去运行已有APP而且写下LOG的需求。

而且代码已经上线了.春...夏...秋...冬...春...夏...秋...冬...春...夏...秋...冬...就这样,三年已往了。一天客户找上门了,公司业务扩展了,现在需要新加3个APP用Monitor自动化。这样我们就必须得改Monitor。

代码实现2://------------------------------------------------------------------------------// <copyright file="Dependency.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestLibrary.ExtensionsClass{ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; public class Monitor { public enum AppNumber { AppOne = 1, AppTwo = 2, AppThree = 3, AppFour = 4, AppFive = 5 } private AppOne appOne = new AppOne(); private AppTwo appTwo = new AppTwo(); private AppThree appThree = new AppThree(); private AppFour appFour = new AppFour(); private AppFive appFive = new AppFive(); private AppNumber number; public Monitor(AppNumber number) { this.number = number; } public bool StartApp() { bool result = false; if (number == AppNumber.AppOne) { result = appOne.Start(); } else if (number == AppNumber.AppTwo) { result = appTwo.Start(); } else if (number == AppNumber.AppThree) { result = appThree.Start(); } else if (number == AppNumber.AppFour) { result = appFour.Start(); } else if (number == AppNumber.AppFive) { result = appFive.Start(); } return result; } public bool ExportAppLog() { bool result = false; if (number == AppNumber.AppOne) { result = appOne.ExportLog(); } else if (number == AppNumber.AppTwo) { result = appTwo.ExportLog(); } else if (number == AppNumber.AppThree) { result = appThree.ExportLog(); } else if (number == AppNumber.AppFour) { result = appFour.ExportLog(); } else if (number == AppNumber.AppFive) { result = appFive.ExportLog(); } return result; } }}代码剖析2:这样会给系统添加新的相互依赖。而且随着时间和需求的推移,会有更多的APP需要用Monitor来监测,这个Monitor工具也会被越来越对的if...else撑爆炸,而且代码随着APP越多,越难维护。

最终会导致Monitor走向死亡(下线)。介于这种情况,可以用Monitor这个模块来生成其它的法式,使得系统能够用在需要的APP上。OOD给我们提供了一种机制来实现这种“依赖倒置”。

代码实现3://------------------------------------------------------------------------------// <copyright file="Dependency.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestLibrary.ExtensionsClass{ using System; public interface IApp { bool Start(); bool ExportLog(); } public class AppOne : IApp { public bool Start() { Console.WriteLine("1号APP开始启动"); return true; } public bool ExportLog() { Console.WriteLine("1号APP输出日志"); return true; } } public class AppTwo : IApp { public bool Start() { Console.WriteLine("2号APP开始启动"); return true; } public bool ExportLog() { Console.WriteLine("2号APP输出日志"); return true; } } public class Monitor { private IApp iapp; public Monitor(IApp iapp) { this.iapp = iapp; } public bool StartApp() { return iapp.Start(); } public bool ExportAppLog() { return iapp.ExportLog(); } }}代码剖析3:现在Monitor依赖于IApp这个接口,而与详细实现的APP类没有关系,所以无论再怎么添加APP都不会影响到Monitor自己,只需要去添加一个实现IApp接口的APP类就可以了。接口隔离原则1.观点: 客户端不应该依赖它不需要的接口,类间的依赖关系应该建设在最小的接口上2.寄义: 接口隔离原则的焦点界说,不泛起臃肿的接口(Fat Interface),可是“小”是有限度的,首先就是不能违反单一职责原则。3.模拟场景: 一个OA系统,外部只卖力提交和撤回事情流,内部卖力审核和驳回事情流。4.代码演示: //------------------------------------------------------------------------------// <copyright file="Dependency.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestLibrary.ExtensionsClass{ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; public interface IReview { void ReviewWorkFlow(); void RejectWorkFlow(); } public class Review : IReview { public void ReviewWorkFlow() { Console.WriteLine("开始审核事情流"); } public void RejectWorkFlow() { Console.WriteLine("已经驳回事情流"); } } public interface ISubmit { void SubmitWorkFlow(); void CancelWorkFlow(); } public class Submit : ISubmit { public void SubmitWorkFlow() { Console.WriteLine("开始提交事情流"); } public void CancelWorkFlow() { Console.WriteLine("已经打消事情流"); } }}5.代码剖析: 其实接口隔离原则很好明白,在上面的例子里可以看出来,如果把OA的外部和内部都界说一个接口的话,那这个接口会很大,而且实现接口的类也会变得臃肿。

合成/聚合复用原则1.观点: 合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)经常又叫做合成复用原则。合成/聚合复用原则就是在一个新的工具内里使用一些已有的工具,使之成为新工具的一部门;新的工具通过向这些工具的委派到达复用已有功效的目的。它的设计原则是:要只管使用合成/聚合,只管不要使用继续。

2.合成/聚合剖析: 聚合观点: 聚适用来表现“拥有”关系或者整体与部门的关系。代表部门的工具有可能会被多个代表整体的工具所共享,而且纷歧定会随着某个代表整体的工具被销毁或破坏而被销毁或破坏,部门的生命周期可以逾越整体。

例如,Iphone5和IOS,当Iphone5删除后,IOS还能存在,IOS可以被Iphone6引用。聚合关系UML类图: 代码演示://------------------------------------------------------------------------------// <copyright file="Dependency.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestLibrary.ExtensionsClass{ class IOS { } class Iphone5 { private IOS ios; public Iphone5(IOS ios) { this.ios = ios; } }}合成观点: 合成用来表现一种强得多的“拥有”关系。在一个合成关系里,部门和整体的生命周期是一样的。

一个合成的新工具完全拥有对其组成部门的支配权,包罗它们的建立和湮灭等。使用法式语言的术语来说,合成而成的新工具对组成部门的内存分配、内存释放有绝对的责任。

一个合成关系中的身分工具是不能与另一个合成关系共享的。一个身分工具在同一个时间内只能属于一个合成关系。如果一个合成关系湮灭了,那么所有的身分工具要么自己湮灭所有的身分工具(这种情况较为普遍)要么就得将这一责任交给别人(较为稀有)。

例如:水和鱼的关系,当水没了,鱼也不行能独立存在。合成关系UML类图: 代码演示: //------------------------------------------------------------------------------// <copyright file="Dependency.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestLibrary.ExtensionsClass{ using System; class Fish { public Fish CreateFish() { Console.WriteLine("一条小鱼儿"); return new Fish(); } } class Water { private Fish fish; public Water() { fish = new Fish(); } public void CreateWater() { // 当建立了一个水的地方,那这个地方也得放点鱼进去 fish.CreateFish(); } }}3.模拟场景: 好比说我们先摇到号(这个比力难题)了,需要为自己买一辆车,如果4S店里的车默认的设置都是一样的。

那么我们只要买车就会有这些设置,这时使用了继续关系:不行能所有汽车的设置都是一样的,所以就有SUV和小轿车两种(只枚举两种比力热门的车型),而且使用灵活车对它们举行聚合使用。这时接纳了合成/聚合的原则:迪米特规则1.观点: 一个软件实体应当尽可能少的与其他实体发生相互作用。每一个软件单元对其他的单元都只有最少的知识,而且局限于那些与本单元密切相关的软件单元。

迪米特规则的初衷在于降低类之间的耦合。由于每个类只管淘汰对其他类的依赖,因此,很容易使得系统的功效模块功效独立,相互之间不存在(或很少有)依赖关系。

迪米特规则不希望类之间建设直接的联系。如果真的有需要建设联系,也希望能通过它的友元类来转达。因此,应用迪米特规则有可能造成的一个结果就是:系统中存在大量的中介类,这些类之所以存在完全是为了通报类之间的相互挪用关系——这在一定水平上增加了系统的庞大度。2.模拟场景: 场景:公司财政总监发出指令,让财政部门的人去统计公司已发公司的人数。

一个常态的编程:(肯定是不符LoD的反例)UML类图:代码演示://------------------------------------------------------------------------------// <copyright file="Dependency.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestLibrary.ExtensionsClass{ using System; using System.Collections.Generic; /// <summary> /// 财政总监 /// </summary> public class CFO { /// <summary> /// 财政总监发出指令,让财政部门统计已发人为人数 /// </summary> public void Directive(Finance finance) { List<Employee> employeeList = new List<Employee>(); // 初始化已发人为人数 for (int i = 0; i < 500; i++) { employeeList.Add(new Employee()); } // 转告财政部门开始统计已结算公司的员工 finance.SettlementSalary(employeeList); } } /// <summary> /// 财政部 /// </summary> public class Finance { /// <summary> /// 统计已结算公司的员工 /// </summary> public void SettlementSalary(List<Employee> employeeList) { Console.WriteLine(string.Format("已结算人为人数:{0}", employeeList.Count)); } } /// <summary> /// 员工 /// </summary> public class Employee { } /// <summary> /// 主法式 /// </summary> public class Runner { public static void main(String[] args) { CFO cfo = new CFO(); // 财政总监发出指令 cfo.Directive(new Finance()); } }}凭据模拟的场景:财政总监让财政部门总结已发人为的人数。财政总监和员工是生疏关系(即总监不需要对员工执行任何操作)。凭据上述UML图和代码解决措施显然可以看出,上述做法违背了LoD规则。

依据LoD规则解耦:(切合LoD的例子)UML类图:代码演示://------------------------------------------------------------------------------// <copyright file="Dependency.cs" company="CNBlogs Corporation">// Copyright (C) 2015-2016 All Rights Reserved// </copyright> //------------------------------------------------------------------------------namespace TestLibrary.ExtensionsClass{ using System; using System.Collections.Generic; /// <summary> /// 财政总监 /// </summary> public class CFO { /// <summary> /// 财政总监发出指令,让财政部门统计已发人为人数 /// </summary> public void Directive(Finance finance) { // 通知财政部门开始统计已结算公司的员工 finance.SettlementSalary(); } } /// <summary> /// 财政部 /// </summary> public class Finance { private List<Employee> employeeList; //通报公司已人为的人 public Finance(List<Employee> _employeeList) { this.employeeList = _employeeList; } /// <summary> /// 统计已结算公司的员工 /// </summary> public void SettlementSalary() { Console.WriteLine(string.Format("已结算人为人数:{0}", employeeList.Count)); } } /// <summary> /// 员工 /// </summary> public class Employee { } /// <summary> /// 主法式 /// </summary> public class Runner { public static void main(String[] args) { List<Employee> employeeList = new List<Employee>(); // 初始化已发人为人数 for (int i = 0; i < 500; i++) { employeeList.Add(new Employee()); } CFO cfo = new CFO(); // 财政总监发出指令 cfo.Directive(new Finance(employeeList)); } }}凭据LoD原则我们需要让财政总监和员工之间没有之间的联系。这样才是遵守了迪米特规则。总结想搞懂设计模式,必须先知道设计模式遵循的六大原则,无论是哪种设计模式都市遵循一种或者多种原则。

这是面向工具稳定的规则。本文针对的是设计模式(面向工具)主要的六大原则展开的解说,并只管做到联合实例和UML类图,资助大家明白。在后续的博文中还会跟进一些设计模式的实例。作者:请叫我头头哥原文:www.cnblogs.com/toutou。


本文关键词:爱游戏APP首页,爱,游戏,APP,首页,专门,画了,9张图,搞懂,前言

本文来源:爱游戏APP下载-www.qzbbc.com


400-888-8888