00.设计模式------设计模式汇总

设计模式(Design Pattern)是针对某一类问题的最优解决方案,是从许多优秀的软件中总结出来的、

设计模式(Design Pattern)是一套经过分类的,被反复使用的软件代码设计经验的总结。

设计模式(Design Pattern)是人们在面对同类型软件工程设计问题所总结出的一些有用经验。模式不是代码,而是某类问题的通用设计解决方案

设计模式(Design Pattern)的本质目的是使软件工程在维护性、扩展性、变化性、复杂度方面成O(N)

使用设计模式是为了可复用代码,让代码更容易被理解,保证代码的可靠性,通常来说,设计模式是软件复用的基础理论,它使代码编制真正工程化、

1.为何使用设计模式(Design Pattern)

  • 复用解决方案:设计模式的主要思想就是 复用,通过复用已经确认的设计,能够在解决问题的过程中使用最小的成本获得最大的利益,而且可以在学习他人的经验的过程中获利,不用在为那些总是会重复出现的问题重复设计解决方案、
  • 设计模式将设计方法标准化:开发团队中的交流和协作通常都要使用共同的词汇和要对问题达成共识,设计模式在项目的分析和设计阶段提供了共同的基准点。
  • 设计模式可以提高个人和团队的设计能力:在开发团队中使用设计模式的经验证明, 设计模式既可以帮助开发人员个人提高水平,也可以帮助团队提供整体实力。
  • 设计模式使软件更容易修改和维护:这是因为这些模式都是久经考验的解决方案。所以,他们的结构都是长期发展形成的。使用设计模式所用的代码往往更易于理解,从而使代码更易于维护。使用设计模式对于开发人员,测试人员都有好处,所以使用设计模式一种多赢的设计方法。

2.设计模式的六大原则

  • Single Responsibility Principle:单一职责原则
  • Open Closed Principle:开闭原则
  • Liskov Substitution Principle:里氏替换原则
  • Law of Demeter:迪米特法则
  • Interface Segregation Principle:接口隔离原则
  • Dependence Inversion Principle:依赖倒置原则

把这六个原则的首字母联合起来(两个 L 算做一个)就是 SOLID (solid,稳定的),其代表的含义就是这六个原则结合使用的好处:建立稳定、灵活、健壮的设计。

1、开闭原则(Open Close Principle)

定义:软件实体应该对扩展开放,对修改关闭。

其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。

软件实体:项目或软件产品中按照一定的逻辑规则划分的模块、抽象和类、方法。

变化的三种类型:

①逻辑变化 

只变化一个逻辑,而不涉及其他模块,比如原有的一个算法是a*b+c,现在需要修改为a*b*c,可以通过修改原有类中的方法的方式来完成,前提条件是所有依赖或关联类都按照相同的逻辑处理。

②子模块变化 

一个模块变化,会对其他的模块产生影响,特别是一个低层次的模块变化必然引起高层模块的变化,因此在通过扩展完成变化时,高层次的模块修改是必然的。

③可见视图变化

可见视图是提供给客户使用的界面,如JSP程序、Swing界面等,该部分的变化一般会引起连锁反应(特别是在国内做项目,做欧美的外包项目一般不会影响太大)。可以通过扩展来完成变化,这要看我们原有的设计是否灵活。

总结:开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类

2、里氏代换原则(Liskov Substitution Principle)

定义:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

(所有引用基类的地方必须能透明地使用其子类的对象。)

通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

定义中包含的四层含义:

1.子类必须完全实现父类的方法

2.子类可以有自己的个性

3.覆盖或实现父类的方法时输入参数可以被放大

        如果父类的输入参数类型大于子类的输入参数类型,会出现父类存在的地方,子类未必会存在,因为一旦把子类作为参数传入,调用者很可能进入子类的方法范畴。

4. 覆写或实现父类的方法时输出结果可以被缩小

      父类的一个方法的返回值是一个类型T,子类的相同方法(重载或覆写)的返回值为S,那么里氏替换原则就要求S必须小于等于T,也就是说,要么S和T是同一个类型,要么S是T的子类。

总结:里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

3、依赖倒置原则(Dependence Inversion Principle)

定义:

①高层模块不应该依赖低层模块,两者都应该依赖其抽象; 

②抽象不应该依赖细节(实现类);  

③细节应该依赖抽象。

依赖倒置原则在java语言中的体现:

①模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;

②接口或抽象类不依赖于实现类;

③实现类依赖接口或抽象类。

依赖的三种写法

①构造函数传递依赖对象(构造函数注入)

②Setter方法传递依赖对象(setter依赖注入)

③接口声明依赖对象(接口注入)

使用原则:

依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合,我们怎么在项目中使用这个规则呢?只要遵循以下的几个规则就可以:

①每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备

②变量的表面类型尽量是接口或者是抽象类

③任何类都不应该从具体类派生(只要不超过两层的继承是可以忍受的)

④尽量不要复写基类的方法

⑤结合里氏替换原则使用

总结:这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

接口分为两种:

实例接口(Object Interface):Java中的类也是一种接口

类接口(Class Interface): Java中经常使用Interface关键字定义的接口

隔离:建立单一接口,不要建立臃肿庞大的接口;即接口要尽量细化,同时接口中的方法要尽量少。

接口隔离原则与单一职责原则的不同:接口隔离原则与单一职责的审视角度是不相同的,单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求接口的方法尽量少。

总结:这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(Demeter Principle)最少知识原则(Least Knowledge Principle, LKP)

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

迪米特法则的意义在于降低类之间的耦合。由于每个对象尽量减少对其他对象的了解,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。

值得一提的是,这一法则却不仅仅局限于计算机领域,在其他领域也同样适用。

总结:

迪米特法则的核心观念就是类间解耦,弱耦合。只有弱耦合了之后,类的复用才可以提高,类变更的风险才可以减低。但解耦是有限度的,除非是计算机的最小单元--二进制的0和1,否则都是存在耦合的。所以在实际项目中,需要适度地参考这个原则,避免过犹不及。

6、单一职责原则 (Single Responsibility Principle

单一职责原则简称 SRP ,顾名思义,就是一个类只负责一个职责。那这个原则有什么用呢,它让类的职责更单一。这样的话,每个类只需要负责自己的那部分,类的复杂度就会降低。如果职责划分得很清楚,那么代码维护起来也更加容易。试想如果所有的功能都放在了一个类中,那么这个类就会变得非常臃肿,而且一旦出现bug,要在所有代码中去寻找;更改某一个地方,可能要改变整个代码的结构,想想都非常可怕。当然一般时候,没有人会去这么写的。

当然,这个原则不仅仅适用于类,对于接口和方法也适用,即一个接口/方法,只负责一件事,这样的话,接口就会变得简单,方法中的代码也会更少,易读,便于维护。

事实上,由于一些其他的因素影响,类的单一职责在项目中是很难保证的。通常,接口和方法的单一职责更容易实现。

单一职责原则的好处

● 类的复杂性降低,实现什么职责都有清晰明确的定义;

● 可读性提高,复杂性降低,那当然可读性提高了; 

● 可维护性提高,可读性提高,那当然更容易维护了; 

●变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮

总结:接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。

单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。

3.设计模式分类

设计模式共分为三类:创建型模式,结构型模式,行为型模式

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
 
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
 
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、
                            备忘录模式、状态模式、访问者模式、中介者模式(调停者模式)、解释器模式。

以下为各种设计模式之间的关系图:

4.简单工厂模式

5.工厂方法模式:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

使用场景:

 1、用户需要一个类的子类的实例,但不希望与该类的子类形成耦合

 2、用户需要一个类的子类的实例,但用户不知道该类有哪些子类可用

优点:

 1、使用工厂方法可以让用户的代码和某个特定类的子类的代码解耦

 2、工厂方法使用户不必知道它所使用的对象是怎样被创建的,只需知道该对象有哪些方法即可。

6.抽象工厂模式:

工厂模式主要就涉及上面介绍的三种:
1、简单工厂模式:是由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。
2、工厂方法模式:是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。
3、抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。

7.创建者模式:

8.原型模式:

9.单例模式:

意义:

  1. 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
  2. 何时使用:当系统需要某个类只有一个实例的时候。
  3. 优点:单例模式的类唯一实例由其本身控制,可以很好的控制用户何时访问它。

应用场景:

  • 需要频繁的进行创建和销毁对象
  • 创建对象时耗时过多或资源消费过多,但又经常使用的对象
  • 工具类对象
  • 频繁访问数据库或文件的对象

10.外观模式:

11.适配器模式:

12.代理模式:

13.装饰模式:

14.桥接模式:

15.组合模式:

16.享元模式

17.模板方法模式:

 

18.观察者模式:

 

19.策略模式:

20.责任链模式:

21.命令模式:

 

22.访问者模式:

23.中介者模式:

24.备忘录模式:

25.迭代器模式:

26.状态模式:

注意:

不要为了套用设计模式而使用设计模式,

应该在遇到问题、想要进行代码优化时想到可不可以用设计模式作为一种解决方案。

好的资源:

设计模式总结

设计模式及其在jdk中案例

发布了141 篇原创文章 · 获赞 27 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/u010581811/article/details/105222775