23中设计模式实例

总结一下23中设计模式各自的优缺点,及实际情况中如何使用。

详细解析如下,使用实例代码地址:https://github.com/chanyi/designPattern

设计模式分为3大类:


创建型模式(5个):

关注点是如何创建一个对象。将创建的使用和分离。使用者只需要使用,不需要关注创建的过程

  • 单例模式:一个类只能提供一个实例,但是可以扩展到优先多例模式;

  • 原型模式:将一个类作为原型,通过复制,制造出多个和原型类似的新实例

  • 工厂模式:定义一个用于创建产品的接口,由子类决定生产什么产品,类创建模式

  • 抽象工厂模式:提供一个创建产品族的接口,每个子类可以创建一系列相关的产品

  • 建造者模式:将一个对象分解成多个部分,然后分别创建他们

结构型模式(7个):
  • 代理模式:控制客户端对对象的访问

  • 适配器模式:将类的接口换成对象需要的

  • 桥接模式:用组合方式代替继承关系

  • 装饰模式:在不改变现有结构的情况下,动态的增加功能

  • 外观模式:facade,为多个子系统提供一个统一的接口

  • 享元模式:共享对象

  • 组合模式:一个对象下,有个列表属性,存放子对象,构成树结构

行为型模式(11个):
  • 模板方法模式:

  • 策略模式:适合用于多个实现方法的统一接口调用的情况。比如排序接口提供一个统一的接口用来被调用,但是排序时实际比较大小的策略可以有多个,比如按照高度比较,按照宽度比较。所以不同的策略可以通过参数入参到排序的方法内。排序方式只是实现排序的代码即可。

  • 命令模式:

  • 责任链模式:

  • 状态模式:

  • 观察者模式:

  • 中介者模式:

  • 迭代器模式:

  • 访问者模式:

  • 备忘录模式:

  • 解释器模式:


创建型模式(5个):

1、单例模式:

特点:

一个类只有一个实例对象

该单例对象必须由单例类

单例类对外提供一个访问该单例类的一个全局访问点

实现:一般可以通过new获取多个实例。所以单例的情况,构造函数要设置为私有的

类内定一个私有静态实例,再定义一个静态公有函数,返回这个私有静态实例

两种方式:懒汉式和饿汉式

懒汉式:类加载的时候没有生成单例,在调用获取单例的方法(getInstance)时才创建单例

饿汉式:类一加载,就同时创建一个单例,在getInstence时单例已经存在

应用场景:

1)、只要求生成一个对象的时候,比如一个人的身份证,一个班的班长

2)、当对象需要被共享的时候,比如数据库的连接池。web中的配置对象,

3)、当某个类频繁被实例话,对象又频繁被销毁的时候。多线程的线程池和网络连接池

线程池在程序中一般只需要一个即可,线程的创建都在线程池内操作。线程池是不变的。网络池的原理相同

扩展:单例模式可以扩展为有限多例模式

将对象创建好后放在一个list里面。这样获取到的实例就是一个list,实现有限个实例。

有限多例的应用场景:比如玩麻将开始需要执两个骰子,此时骰子作为一个类的话,就需要创建两个实例。

2、原型模式:用一个已经创建的实例当作原型,复制出多个实例来。

java提供了对象的clone方法,实现原型模式很简单

分类:

深克隆:自己完成每个属性的clone

浅克隆:只需要调用clone即可

优点:

1、简化流程

2、动态获取对象

3、某些情况下比直接new快一些

3、工厂方法模式(FactoryMethod)

抽象工厂接口中只生产一个产品

接口:定义一个工厂接口,里面包含创建对象方法

工厂子类:实现工厂接口,实现具体的创建对象方法

分类:

简单工厂模式:创建的产品不多,只要一个工厂类就可以完成(无抽象工厂类)

抽象工厂模式:在不修改源代码的情况下,引入新的产品(有抽象工厂类)

使用于:

用户只知道产品工厂名,不知道产品类型

客户不关心创建的过程,只关心产品的品牌

易于扩展,如果新增一个具体产品,则新建一个具体工厂,继承抽象工厂。在新建的工厂中写代码,不影响原来的代码

实例:

使用工厂方法模式写一个计算器(面试)

思路:

抽象工厂接口:计算接口,方式是返回结果

具体工厂类:加法工厂类,乘法工厂类,除法工厂类,减法工厂类。。。

调用类:直接使用具体的工厂类创建一个对象,调用返回结果方法,即可;

4、抽象工厂模式(abstractFactory)

抽象工厂接口中可以生成两个及多个产品

工厂方法模式只生产一个等级的产品,抽象工厂可以生产多个等级的产品

使用条件:

1、系统中有多个产品族,每个具体的工厂产生一族产品

2、系统一次只可能生产某一族产品,同族的产品一起使用

优点:

对同族多产品共同管理

增加一个新的产品族时不需要修改源代码,满足开闭原则

缺点:

如果产品族中增加一个新产品,整个工厂都要修改

5、建造者模式:

使用多个简单的对象,一步一步构建成一个复杂的对象

将一个复杂的对象拆分成多个简单的对象

使用的实例:

套餐的组成(拆分成多个简单的组成),StringBuilder,

优点:

容易扩展,便于控制细节风险

缺点:

如果内部复杂会有多个建造类

产品必须要有共同点

注意:

和抽象工厂模式相比,更加注重各个组成部分的顺序


结构型模式:

1、代理模式(proxy):

为对象提供一种代理,以控制对象的访问,客户端通过代理访问对象,可以控制客户端对对象属性的访问和操作

实例:

下载很大文件,需要时间比较长

单位内部数据库,限制客户端的访问

优点:

起中介作用,保护目标对象

对目标对象的功能进行扩展

目标对象与客户端分离,可以降低系统的耦合度

缺点:

有了中介,请求速度变慢

增加系统的复杂度

结构:

真实类

抽象类(接口/抽象类)

代理类

2、适配器模式(adapter):将一个类的接口换成客户端所需要的接口,比如将交流电转为直流电供笔记本电脑使用

优点;

将已有的类放到新环境下,使之适应新的需求

可以让两个没有关联的类一起运行

提高了类的复用性

提高类的透明度

灵活性好

缺点:

过多适配器会是系统变得复杂

java是单继承类,最多只能适配一个类

3、桥接模式(bridge):抽象与实现分离,二者可以独立变化,用组合关系代替继承关系,降低了耦合度

优点:

降低耦合度,扩展性强

细节对客户透明

缺点:

设计难度大,对系统要有深入的理解

结构:

抽象类

扩展抽象类

实现类

具体实现类

适用:

一个类有两个独立变化的维度

4、装饰模式(decorator):在不改变现有结构的情况下,动态的给对象增加一些职责

优点:

比继承更灵活

可以设计出不同的装饰类,创造出多个不同行为的组合

缺点:

增加许多子类,增加复杂度

结构:

抽象类

具体类

抽象装饰类:增加一个抽象类的属性,

具体装饰类:具体装饰类继承抽象装饰类,重写抽象装饰类继承的抽象类的抽象方法,然后改写实现动态增加

5、外观模式(facade):为多个复杂的子系统提供一个统一而接口,是其他客户只需要访问这一个接口即可,不需要按个访问每一个复杂的子系统

优点:

降低子系统与客户端的耦合度

减少客户端处理的子系统对象的数量,子系统用起来更方便

编译一个子系统不会影响其他的子系统和客户端

缺点:

不能很好的限制客户使用子系统的类

增加新系统,要修改统一接口,不满足开闭原则

适用场景:

子系统很多的系统

客户端和多个子系统之间有联系的时候

6、享元模式(flyweight):利用共享技术,重用细粒度的对象。减少系统开销

优点:

减少系统开销

缺点:

对象共享,增加程序的复杂度

读取享元模式的外部状态,是运行时间稍微变长

两种状态:

内部状态:不会随着环境改变的内部共享部分

外部状态:随环境改变的外部不可共享的部分

7、组合模式(composite):

在一个对象中包含其他对象,多个对象形成一个树形结构

主要适用于树形结构的对象的情况

优点:

高层模块调用简单,增加子节点自由

缺点:

实现是 叶子和树枝都是实现类,不是接口,违反了依赖倒置原则

行为型模式(11个)

1、模板方法:定义一个操作中的算法骨架,子类实现算法的具体步骤,主要就是封装不可变性,扩展可变性

优点:

父类中封装共用代码,便于代码的复用

部分方法有子类实现,符合开闭原则,

缺点:

每一个具体算法的实现都有有一个对应的子类,类比较多,不好维护

父类的抽象方法由子类实现,子类执行的结果会影响父类的结果,导致一种反向的控制结构,提高代码的阅读难度

结构:

抽象类:给出整个框架,由一个模板方法(定义算法骨架)和几个基本方法构成(算法的具体步骤)

具体子类:实现抽象类的抽象方法

2、策略模式(strategy)定义一系列算法,把每个算法封装起来,算法之间可以相互替换。而且算法的变化不会影响使用。

优点:

替代多重条件判断的方法,这样易于维护

一系列的算法族中的公共部分可以抽取到父类中,避免重复代码

支持开闭原则

算法族的实现放在策略类中,算法族的使用放在使用类中。二者分离

缺点:

策略模式需要很多策略类

对算法的选择需要慎重的考虑

构成:

抽象策略类

具体策略类

使用类(环境类)

应用实际场景:

诸葛亮锦囊,一个锦囊就是一个策略。

多种出行方法,一种出行方式就是一个策略

3、命令模式(command):请求以命令的形式包裹在对象中,并传给调用对象,

调用对象寻找可以处理该命令的合适的对象,然后把命令传给相应的对象,对该对象执行命令

优点:

将行为请求者和行为实现者解耦

新的命令很容易加入到系统中

缺点:

系统会有过多的具体命令类

结构:

调用者:有一个命令对象,在某个时间点调用命令对象的execute方法

命令对象:持有一个接受者和一个execute方法

接受者:动作的执行者

4、责任链模式(chain of Responsibility)

请求发送到责任链上,不需要关注处理的系统和请求的传递过程

优点:

降低对象之间的

增强系统的可扩展性

增加给对象指派责任的灵活性

责任的分担,每个类处理自己的责任,符合类的职责单一原则

缺点:

不能保证每个请求一定被处理,一个请求如果没有明确的接受者,这个请求可能传递到责任链的最后还没被处理

责任链长的情况,请求的处理可能会涉及多个处理对象,影响系统性能

责任链建立的合理性靠客户端来保证。增加客户端你的负责性

结构:

抽象处理者(handler)

具体处理者(concreteHandler)

客户端(client)

使用实例:

请假找不同的领导,不同的领导又不同的责任,批假的权限也都不相同

5、状态模式(state):

把复杂的判断逻辑提取到不同的状态对象中,允许状态对象在其内部状态发生改变是改变其行为

优点:

将特定状态的相关行为局部化到一个状态中,将不同状态分离开,满足单一职责原则

减少对象的相互依赖

有利于扩展,有新的状态,就直接定义一个新的状态类

缺点:

增加类和对象的个数

容易造成代码混乱

结构:

环境角色(context)

抽象状态(state)

具体状态(concreteState)

6、观察者模式(observer)

多个对象之间存在着一对多的依赖关系,当一个对象的状态发生变化,其他对象的行为也跟着发生变化

也称为订阅发布,模型视图模式

优点:

降低了目标与观察者之间的耦合关系,

目标与观察者之间建立一套触发机制

缺点:

目标与观察者依赖关系没有完全解除

当观察者对象很多的时候,通知发布会花费很多时间,影响性能

结构:

抽象主题(subject)抽象目标类:

具体主题(concrete subject)

抽象观察者(observer)

具体观察者(concrete observer)

7、中介者模式(mediator)

为了降低多个对象和类之间的通信复杂性,使用中介类,处理不同类的通信,支持松耦合,解决网状结构

优点:

减低对象之间的耦合度

将对象间的一对多关联变成一对一关联,提高系统的易维护性

缺点:

对象太多的时候,中介者对象会变的很复杂

结构:

抽象中介类(mediator)

具体中介类(concrete mediator)

抽象同事类(colleague)

具体同事类(concrete colleague)

8、迭代器模式(Iterator)

提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示

优点:

简化聚合类,遍历任务给遍历器类

封装性好,为遍历不同的聚合结构提供统一的接口

增加新的聚合类,新的遍历器类都很方便,无需修改原有代码

缺点:

增加类的个数,增加复杂度

结构:

抽象聚合类(Aggregate)

具体聚合类(concreteAggregate)

抽象迭代器(Iterator)

具体迭代器类(concreteIterator)

9、访问者模式(visitor)

将某种数据结构中的各元素的操作分离出来封装成独立的类,某些元素的有了新的操作,就定义新的类,不影响原有的数据结构

为每个数据元素中的元素提供多种访问方式

优点:

扩展性好

复用性好

灵活性好

符合单一职责原则

缺点:

每增加一个新的元素类,就需要增加一系列的访问类,违背开闭原则

破坏封装性,具体的元素对访问者公开

违反了依赖倒置原则,访问者类依赖了具体类,没有依赖抽象类

结构:

抽象访问者(visitor)

具体访问者(visitorConcrete)

抽象元素(element)

具体元素(elementConcrete)

对象结构(Object Structure)

10、备忘录模式(memento)

在不破坏封装性的前提下,捕获一个对象的内部状态,并缓存,当需要的时候把对象回复原来的状态,也是一种快照模式

优点:

提供一种可以回复状态的机制,

实现内部封装,除创建人外,其他人都不能访问

简化发起人类,回复过程直接由管理者管理,符合单一职责原则

缺点:

资源消耗大,要花内存去存储快照数据

结构:

发起人(Originator)

备忘录(memento)

管理者(caretaker)

11、解释器模式(interpreter)

给分析对象定义一个语言,定义语言的文法,然后再用解释器解析,该接口解释一个特定的上下文

优点:

扩展性好,使用类来解释文法,可以继承

容易实现,语法树中的每个表达式节点类都是相似的,实现文法比较容易

缺点:

执行效率低:解释器中有很多的循环和递归

会引起类膨胀,每条规则至少定义一个类

可用场景比较少

结构:

抽象表达式(Expression)

终止符表达式(Terminal Expression)

非终止符表达式(Notterminal Expression)

环境角色(context)

客户端(client)

你可能感兴趣的:(23中设计模式实例)