23种设计模式_23种设计模式知识点整理,建议收藏

设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。

1995 年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了 23 种设计模式,从此树立了软件设计模式领域的里程碑,人称「GoF设计模式」。

这 23 种设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性,以及类的关联关系和组合关系的充分理解。

当然,软件设计模式只是一个引导,在实际的软件开发中,必须根据具体的需求来选择:

  • 对于简单的程序,可能写一个简单的算法要比引入某种设计模式更加容易;

  • 但是对于大型项目开发或者框架设计,用设计模式来组织代码显然更好。

为了让大家快速的、整体的学习和使用设计模式,老谭整理了23种设计模式的重要知识点,希望对您有所帮助。enjoy~

发送私信“设计模式”,获取可编辑的类图文件。

1、单例模式(Singleton Pattern)

定义

Ensure a class has only one instance, and provide a global point of access to it.

某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。

类图

545e9428d366ee08cc0a83b0143105d9.png

使用场景

● 要求生成唯一序列号的环境;

● 在整个项目中需要一个共享访问点或共享数据,例如一个 Web 页面上的计数 器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确 保证线程安全的;

● 创建一个对象需要消耗的资源过多,如要访问 IO 和数据库等资源;

● 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式 (当然,也可以直接声明为 static 的方式)。

2、工厂模式(Factory Pattern)

定义

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer intantiation to subclasses.

定义了一个创建对象的接口,由子类来决定详细实例化那个对象。工厂方法模式让类的实例化转移到子类中来推断。

类图

dc1fffa21e213d8623802085dfca679a.png

简单工厂模式一个模块仅需要一个工厂类,没有必要把它产生出来,使用静态的方法

多个工厂类每个人种(具体的产品类)都对应了一个创建者,每个创建者独立负责创建对应的 产品对象,非常符合单一职责原则

代替单例模式单例模式的核心要求就是在内存中只有一个对象,通过工厂方法模式也可以只在内 存中生产一个对象

延迟初始化ProductFactory 负责产品类对象的创建工作,并且通过prMap 变量产生一个缓 存,对需要再次被重用的对象保留

使用场景

jdbc 连接数据库,硬件访问,降低对象的产生和销毁

3、抽象工厂(Abstract Factory Pattern)

定义

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类 – 客户端不必指定产品的具体类型,创建多个产品族中的产品对象

类图

d5ecc36c521ed62bfe6710808efd0b36.png

使用场景

一个对象族(或是一组没有任何关系的对象)都有相同的约束。涉及不同操作系统的时候,都可以考虑使用抽象工厂模式

4、建造者模式(Builder Pattern)

定义

Seperate the constraction of a complex object from its representation so that the same construction process can create different representations.

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

类图

9a3ffd382e1614de5871b8a5a50d31be.png

● Product 产品类通常是实现了模板方法模式,也就是有模板方法和基本方法,例子中的 BenzModel 和 BMWModel 就属于产品类。

● Builder 抽象建造者规范产品的组建,一般是由子类实现。例子中的 CarBuilder 就属于抽象建造者。

● ConcreteBuilder 具体建造者实现抽象类定义的所有方法,并且返回一个组建好的对象。例子中的 BenzBuilder 和 BMWBuilder 就属于具体建造者。

● Director 导演类负责安排已有模块的顺序,然后告诉 Builder 开始建造

使用场景

● 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。

● 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时, 则可以使用该模式。

● 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使 用建造者模式非常合适。

建造者模式与工厂模式的不同

建造者模式最主要的功能是基本方法的调用顺序安排,这些基本方法已经实现了, 顺序不同产生的对象也不同;工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。

5、代理模式(Proxy Pattern)

定义

Provide a surrogate or placeholder for another object to control access to it

为其他对象提供一种代理以控制对这个对象的访问

类图

5c069b1f2db9f36df14bddf2f35f2175.png

● Subject 抽象主题角色抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要 求。

● RealSubject 具体主题角色也叫做被委托角色、被代理角色。它才是冤大头,是业务逻辑的具体执行者。

● Proxy 代理主题角色也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法 限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后 处理工作。

普通代理和强制代理

普通代理就是我们要知道代理的存在,也就是类似的 GamePlayerProxy 这个类的 存在,然后才能访问;强制代理则是调用者直接调用真实角色,而不用关心代理是否存在,其代理的产生 是由真实角色决定的。

普通代理: 在该模式下,调用者只知代理而不用知道真实的角色是谁,屏蔽了真实角色的变更 对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模块没有 任何的影响,只要你实现了接口所对应的方法,该模式非常适合对扩展性要求较高 的场合。强制代理:强制代理的概念就是要从真实角色查找到代理角色,不允许直接访问真实角色。高 层模块只要调用 getProxy 就可以访问真实角色的所有方法,它根本就不需要产生 一个代理出来,代理的管理已经由真实角色自己完成。

动态代理: 根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称“我 已经实现该接口下的所有方法了”。两条独立发展的线路。动态代理实现代理的职责,业务逻辑 Subject 实现相关的逻 辑功能,两者之间没有必然的相互耦合的关系。通知 Advice 从另一个切面切入, 最终在高层模块也就是 Client 进行耦合,完成逻辑的封装任务。

6、模板方法模式(Template Method Pattern)

定义

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain stops of an algorithm without chaning the algorithm's structure

定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

类图

8c57109835c07cddb059ea8b8dbe290f.png

AbstractClass 叫做抽象模板,它的方法分为两类:

● 基本方法基本方法也叫做基本操作,是由子类实现的方法,并且在模板方法被调用。

● 模板方法可以有一个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调 度,完成固定的逻辑。注意:为了防止恶意的操作,一般模板方法都加上 final 关键字,不允许被覆 写。具体模板:ConcreteClass1 和ConcreteClass2 属于具体模板,实现父类所定义的 一个或多个抽象方法,也就是父类定义的基本方法在子类中得以实现

使用场景

● 多个子类有公有的方法,并且逻辑基本相同时。

● 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由 各个子类实现。

● 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然 后通过钩子函数约束其行为。

7、原型模式(Prototype Pattern)

定义

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

采用复制已有对象实例来产生新的对象实例。

类图

7a21f097bcf9e8173a80b89706538ceb.png

使用原型模式的优点

● 性能优良原型模式是在内存二进制流的拷贝,要比直接 new 一个对象性能好很多,特别是 要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。

● 逃避构造函数的约束这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的

使用场景

● 资源优化场景类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

● 性能和安全要求的场景通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模 式。

● 一个对象多个修改者的场景一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以 考虑使用原型模式拷贝多个对象供调用者使用。

浅拷贝和深拷贝

浅拷贝:Object 类提供的方法 clone 只是拷贝本对象,其对象内部的数组、引用 对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝,其 他的原始类型比如 int、long、char、string(当做是原始类型)等都会被拷贝。注意:使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是 类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个 原始类型或不可变对象。

深拷贝:对私有的类变量进行独立的拷贝如:thing.arrayList = (ArrayList)this.arrayList.clone();

8、中介者模式(Mediator Pattern)

定义

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

定义一个对象,这个对象封装了一组对象的交互。中介者模式通过使各个对象之间不用显示交互,来解耦各个对象,并且 中介者 模式允许 对象独立的改变他的交互。

类图

414ca5400acc6dd72a86f7b6a4528bd2.png

● Mediator 抽象中介者角色抽象中介者角色定义统一的接口,用于各同事角色之间的通信。

● Concrete Mediator 具体中介者角色具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角 色。

● Colleague 同事角色每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通 过中介者角色协作。

每个同事类的行为分为两种:

一种是同事本身的行为,比如改 变对象本身的状态,处理自己的行为等,这种行为叫做自发行为(Self- Method),与其他的同事类或中介者没有任何的依赖;

第二种是必须依赖中介者 才能完成的行为,叫做依赖方法(Dep-Method)。

使用场景

中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出 现了蜘蛛网状结构,即每个类都与其他的类有直接的联系。

9、命令模式(Command Pattern)

定义

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能

类图

2631f6c7564960e2356c414784ee9741.png

● Receive 接收者角色该角色就是干活的角色,命令传递到这里是应该被执行的,具体到我们上面的例子 中就是 Group 的三个实现类(需求组,美工组,代码组)。

● Command 命令角色需要执行的所有命令都在这里声明。

● Invoker 调用者角色接收到命令,并执行命令。在例子中,我(项目经理)就是这个角色。

使用场景

认为是命令的地方就可以采用命令模式,例如,在 GUI 开发中,一个按钮的点击 是一个命令,可以采用命令模式;模拟 DOS 命令的时候,当然也要采用命令模式;触发-反馈机制的处理等。

10、责任链模式(Chain of Responsibility Pattern)

定义

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

类图

c18dc7238b075f100599e80c4fcfda07.png

抽象的处理者实现三个职责:

一是定义一个请求的处理方法 handleMessage,唯一对外开放的方法;

二是定义一个链的编排方法 setNext,设置下一个处理者;

三是定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别 getHandlerLevel 和具体的处理任务 echo。

注意事项

链中节点数量需要控制,避免出现超长链的情况,一般的做法是在 Handler 中设置 一个最大节点数量,在 setNext 方法中判断是否已经是超过其阈值,超过则不允许 该链建立,避免无意识地破坏系统性能。

11、装饰模式(Decorator Pattern)

定义

Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

类图

9b00b3fcd650a2869724f3a5104a58ff.png

● Component 抽象构件Component 是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原 始的对象,如上面的成绩单。注意:在装饰模式中,必然有一个最基本、最核心、最原始的接口或抽象类充当 Component 抽象构件。

● ConcreteComponent 具体构件ConcreteComponent 是最核心、最原始、最基本的接口或抽象类的实现,你要装 饰的就是它。

● Decorator 装饰角色一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象 的方法呀,在它的属性里必然有一个 private 变量指向 Component 抽象构件。

● 具体装饰角色ConcreteDecoratorA 和 ConcreteDecoratorB 是两个具体的装饰类,你要把你最核 心的、最原始的、最基本的东西装饰成其他东西,上面的例子就是把一个比较平庸 的成绩单装饰成家长认可的成绩单。

使用场景

● 需要扩展一个类的功能,或给一个类增加附加功能。

● 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

● 需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式。

12、策略模式(Strategy Pattern)

定义

Define a family of algorithms, encapsulate each one, and make them interchangeable.

定义一组算法,将每个算法都封装起来,并且使他们之间可以互换

类图

e4de55cf0e639fa5dddc06eb31d2d87f.png

● Context 封装角色它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访 问,封装可能存在的变化。

● Strategy 抽象策略角色策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属 性。各位看官可能要问了,类图中的 AlgorithmInterface 是什么意思,嘿嘿, algorithm 是“运算法则”的意思,结合起来意思就明白了吧。

● ConcreteStrategy 具体策略角色(多个)实现抽象策略中的操作,该类含有具体的算法。

使用场景

● 多个类只有在算法或行为上稍有不同的场景。

● 算法需要自由切换的场景。

● 需要屏蔽算法规则的场景。

注意事项:具体策略数量超过 4 个,则需要考虑使用混合模式

13、适配器模式(Adapter Pattern)

定义

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that could't otherwise because of incompatible interfaces.

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

类图

aa3678262a92d924d34ea99884a6861b.png

类适配器

● Target 目标角色该角色定义把其他类转换为何种接口,也就是我们的期望接口,例子中的 IUserInfo 接口就是目标角色。

● Adaptee 源角色你想把谁转换成目标角色,这个“谁”就是源角色,它是已经存在的、运行良好的类 或对象,经过适配器角色的包装,它会成为一个崭新、靓丽的角色。

● Adapter 适配器角色适配器模式的核心角色,其他两个角色都是已经存在的角色,而适配器角色是需要 新建立的,它的职责非常简单:把源角色转换为目标角色,怎么转换?通过继承或 是类关联的方式。

对象适配器和类适配器的区别:

类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系, 这是两者的根本区别。(实际项目中对象适配器使用到的场景相对比较多)。

使用场景

你有动机修改一个已经投产中的接口时,适配器模式可能是最适合你的模式。比如 系统扩展了,需要使用一个已有或新建立的类,但这个类又不符合系统的接口,怎 么办?使用适配器模式,这也是我们例子中提到的。

注意事项:详细设计阶段不要考虑使用适配器模式,使用主要场景为扩展应用中。

14、迭代器模式(Iterator Pattern)

定义

Provide a way to access the elements of an aggregate object sequencially without exposing its underlying represetation.

它提供一种方法访问一个容器对 象中各个元素,而又不需暴露该对象的内部细节。

类图

ec9e9b8cf7c5be76a09295fd5709998f.png

● Iterator 抽象迭代器抽象迭代器负责定义访问和遍历元素的接口,而且基本上是有固定的 3 个方法:first()获得第一个元素,next()访问下一个元素,isDone()是否已经访问到底部(Java 叫做 hasNext()方法)。

● ConcreteIterator 具体迭代器具体迭代器角色要实现迭代器接口,完成容器元素的遍历。

● Aggregate 抽象容器容器角色负责提供创建具体迭代器角色的接口,必然提供一个类似 createIterator() 这样的方法,在 Java 中一般是 iterator()方法。

● Concrete Aggregate 具体容器具体容器实现容器接口定义的方法,创建出容纳迭代器的对象。ps:迭代器模式已经被淘汰,java 中已经把迭代器运用到各个聚集类(collection)中了,使用 java 自带的迭代器就已经满足我们的需求了。

15、组合模式(Composite Pattern)

定义

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对于单个对象和组合对象的使用具有一致性。

类图

565fea9a6492e20045d70cfae95daa2a.png

● Component 抽象构件角色定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性,比如我们 例子中的 getInfo 就封装到了抽象类中。

● Leaf 叶子构件叶子对象,其下再也没有其他的分支,也就是遍历的最小单位。

● Composite 树枝构件树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构。

使用场景

● 维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理。

● 从一个整体中能够独立出部分模块或功能的场景。

注意

只要是树形结构,就考虑使用组合模式。

16、观察者模式(Observer Pattern)

定义

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于 它的对象都会得到通知并被自动更新。

类图

268e39bd2f8f0f7f79717dcacd4d4ac0.png

● Subject 被观察者定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽 象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观 察者。

● Observer 观察者观察者接收到消息后,即进行 update(更新方法)操作,对接收到的信息进行处 理。

● ConcreteSubject 具体的被观察者定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

● ConcreteObserver 具体的观察者每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。

使用场景

● 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。

● 事件多级触发场景。

● 跨系统的消息交换场景,如消息队列的处理机制。

注意

● 广播链的问题在一个观察者模式中最多出现一个对象既是观察者也是被观察者,也就是说消息最 多转发一次(传递两次)。

● 异步处理问题观察者比较多,而且处理时间比较长,采用异步处理来考虑线程安全和队列的问 题。

17、门面模式(Facade Pattern)

定义

Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

要求一 个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个 高层次的接口,使得子系统更易于使用。

类图

5f4ce37402d27f34cbb7807d099ec31f.png

● Facade 门面角色客户端可以调用这个角色的方法。此角色知晓子系统的所有功能和责任。一般情况 下,本角色会将所有从客户端发来的请求委派到相应的子系统去,也就说该角色没 有实际的业务逻辑,只是一个委托类。

● subsystem 子系统角色可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类 的集合。子系统并不知道门面的存在。对于子系统而言,门面仅仅是另外一个客户 端而已。

使用场景

● 为一个复杂的模块或子系统提供一个供外界访问的接口

● 子系统相对独立——外界对子系统的访问只要黑箱操作即可

● 预防低水平人员带来的风险扩散

注意

●一个子系统可以有多个门面

●门面不参与子系统内的业务逻辑

18、备忘录模式(Memento Pattern)

定义

Without violating encapsulation. capture and externalize an object's internal state so that the object can be restored to this state later.

在不破坏封装性的前提 下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该 对象恢复到原先保存的状态。

类图

3c441a3ff8dd4642543cf3bf8c4b8d1f.png

● Originator 发起人角色记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备 忘录数据。

● Memento 备忘录角色(简单的 javabean)负责存储 Originator 发起人对象的内部状态,在需要的时候提供发起人需要的内部 状态。

● Caretaker 备忘录管理员角色(简单的 javabean)对备忘录进行管理、保存和提供备忘录。

几种备忘录模式

clone 方式备忘录:

● 发起人角色融合了发起人角色和备忘录角色,具有双重功效

多状态的备忘录模式

● 增加了一个 BeanUtils 类,其中 backupProp 是把发起人的所有属性值转换到 HashMap 中,方便备忘录角色存储。restoreProp 方法则是把HashMap 中的值返 回到发起人角色中。

多备份的备忘录:略封装得更好一点:保证只能对发起人可读

●建立一个空接口 IMemento——什么方法属性都没有的接口,然后在发起人 Originator 类中建立一个内置类(也叫做类中类)Memento 实现IMemento 接口, 同时也实现自己的业务逻辑。

使用场景

● 需要保存和恢复数据的相关状态场景。

● 提供一个可回滚(rollback)的操作。

● 需要监控的副本场景中。

● 数据库连接的事务管理就是用的备忘录模式。

注意

●备忘录的生命期

●备忘录的性能不要在频繁建立备份的场景中使用备忘录模式(比如一个for 循环中)。

19、访问者模式(Visitor Pattern)

定义

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

类图

20a0eb92739bd6b1320ac3af7b1c811b.png

● Visitor——抽象访问者抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是 visit 方法的 参数定义哪些对象是可以被访问的。

● ConcreteVisitor——具体访问者它影响访问者访问到一个类后该怎么干,要做什么事情。

● Element——抽象元素接口或者抽象类,声明接受哪一类访问者访问,程序上是通过 accept 方法中的参 数来定义的。

● ConcreteElement——具体元素实现 accept 方法,通常是 visitor.visit(this),基本上都形成了一种模式了。

● ObjectStruture——结构对象元素产生者,一般容纳在多个不同类、不同接口的容器,如 List、Set、Map 等, 在项目中,一般很少抽象出这个角色。

使用场景

● 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些 依赖于其具体类的操作,也就说是用迭代器模式已经不能胜任的情景。

● 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这 些操作“污染”这些对象的类。

20、状态模式(State Pattern)

定义

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

当一个对象内在状态改变时允许其改变行 为,这个对象看起来像改变了其类。

类图

db72e570b796e7a4984cdf45068aaffd.png

● State——抽象状态角色接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。

● ConcreteState——具体状态角色每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地 说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。

● Context——环境角色定义客户端需要的接口,并且负责具体状态的切换。

使用场景

● 行为随状态改变而改变的场景这也是状态模式的根本出发点,例如权限设计,人员的状态不同即使执行相同的行 为结果也会不同,在这种情况下需要考虑使用状态模式。

● 条件、分支判断语句的替代者

注意

状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的 变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的 状态最好不要超过 5 个。

21、解释器模式(Interpreter Pattern)

定义

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

类图

d56e9406b259d2359dc76657009e5d1c.png

● AbstractExpression——抽象解释器具体的解释任务由各个实现类完成,具体的解释器分别由 TerminalExpression 和 Non-terminalExpression 完成。

● TerminalExpression——终结符表达式实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表 达式,但有多个实例,对应不同的终结符。具体到我们例子就是 VarExpression 类,表达式中的每个终结符都在栈中产生了一个 VarExpression 对象。

● NonterminalExpression——非终结符表达式文法中的每条规则对应于一个非终结表达式,具体到我们的例子就是加减法规则分 别对应到 AddExpression 和 SubExpression 两个类。非终结符表达式根据逻辑的 复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

● Context——环境角色具体到我们的例子中是采用 HashMap 代替。

使用场景

● 重复发生的问题可以使用解释器模式

● 一个简单语法需要解释的场景

注意

尽量不要在重要的模块中使用解释器模式,否则维护会是一个很大的问题。在项目 中可以使用 shell、JRuby、Groovy 等脚本语言来代替解释器模式,弥补Java 编 译型语言的不足。

22、享元模式(Flyweight Pattern)

定义

Use sharing to support large numbers of fine-grained objects effciently.

使用共享对象可有效地支持大量的细粒度的对象。

类图

e5bd54a05aa6fda1f8bc6bb79a5626ef.png

对象的信息分为两个部分:内部状态(intrinsic)与外部状态(extrinsic)。

● 内部状态内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改 变。

● 外部状态外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状 态。

● Flyweight——抽象享元角色它简单地说就是一个产品的抽象类,同时定义出对象的外部状态和内部状态的接口 或实现。

● ConcreteFlyweight——具体享元角色具体的一个产品类,实现抽象角色定义的业务。该角色中需要注意的是内部状态处 理应该与环境无关,不应该出现一个操作改变了内部状态,同时修改了外部状态, 这是绝对不允许的。

● unsharedConcreteFlyweight——不可共享的享元角色不存在外部状态或者安全要求(如线程安全)不能够使用共享技术的对象,该对象 一般不会出现在享元工厂中。

● FlyweightFactory——享元工厂职责非常简单,就是构造一个池容器,同时提供从池中获得对象的方法。

使用场景

● 系统中存在大量的相似对象。

● 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对 象没有特定身份。

● 需要缓冲池的场景。

注意

● 享元模式是线程不安全的,只有依靠经验,在需要的地方考虑一下线程安全,在 大部分场景下不用考虑。对象池中的享元对象尽量多,多到足够满足为止。

● 性能安全:外部状态最好以 java 的基本类型作为标志,如 String,int,可以提 高效率。

23、桥梁模式(Bridge Pattern)

定义

Decouple an abstraction from its implementation so that the two can vary independently

将抽象和实现解耦,使得两者可以独立地变化。

类图

06a9184866bf88b640150022c424218f.png

● Abstraction——抽象化角色它的主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色 一般是抽象类。

● Implementor——实现化角色它是接口或者抽象类,定义角色必需的行为和属性。

● RefinedAbstraction——修正抽象化角色它引用实现化角色对抽象化角色进行修正。

● ConcreteImplementor——具体实现化角色它实现接口或抽象类定义的方法和属性。

使用场景

● 不希望或不适用使用继承的场景

● 接口或抽象类不稳定的场景

● 重用性要求较高的场景

注意

发现类的继承有 N 层时,可以考虑使用桥梁模式。桥梁模式主要考虑如何拆分抽 象和实现。

发送私信“设计模式”,获取可编辑的类图文件。

正文部分

250adead70e835589306d9d6d3a906e4.png

《程序员的思维修炼》是菜根老谭结合自己的工作经历和对这个岗位发展的认知而专门开辟的一个专栏,旨在分析程序员的职业发展的过程中我们应该锻炼哪些思维意识,如何去合理正确的看待事物,如何形成适合自己发展的思维体系。本专栏既是对过去思考的总结,也是对自己发展所具备的能力的思考,希望这些内容能陪我成长,帮大家解疑答惑。 该专栏首发今日头条,关注我的同名头条号获取更及时的内容推荐。

同时,微信为菜根老谭开通了视频号,配合着一些短视频,讲讲产品研发的那点事,分析产品研发过程中出现的问题以及思考。

33ca6142887ed3eba6559721b1cac097.png

菜根老谭,微信公众号:CGLT_TAN,人人都是产品经理专栏作家。经历程序员、技术Leader、研发Leader等多种岗位。关注医疗,早教领域,擅长企业IT架构及互联网产品架构。

点击“阅读原文”,获取《程序员的思维修炼》专栏文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基本信息 原书名: Design Patterns:Elements of Reusable Object-Oriented software 原出版社: Addison Wesley/Pearson 作者: (美)Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides [作译者介绍] 译者: 李英军 马晓星 蔡敏 刘建中 丛书名: 计算机科学丛书 出版社:机械工业出版社 ISBN:7111075757 上架时间:2005-7-19 出版日期:2004 年9月 开本:16开 页码:254 版次:1-11 内容简介   本书结合设计实例从面向对象的设计中精选出23个设计模式,总结了面向对象设计中最有价值的经验,并且用简洁可复用的形式表达出来。本书分类描述了一组设计良好、表达清楚的软件设计模式,这些模式在实用环境下特别有用。本书适合大学计算机专业的学生、研究生及相关人员参考。       [strong][font color="#ff0000"]书评[/font][/strong][font color="#ff0000"]       “这本众人期待的确达到了预期的全部效果。该书云集了经过时间考验的可用设计。作者从多年的面向对象设计经验中精选了23个模式,这构成了该书的精华部份,每一个精益求精的优秀程序员都应拥有这本《设计模式》。”--larry o'brien, software development       “[设计模式]在实用环境下特别有用,因为它分类描述了一组设计良好,表达清楚的面向对象软件设计模式。整个设计模式领域还很新,本书的四位作者也许已占据了这个领域造诣最深的专家中的半数,因而他们定义模式的方法可以作为后来者的榜样。如果要知道怎样恰当定义和描述设计模式,我们应该可以从他们那儿获得启发”--steve billow, journal of object-oriented programming       “总的来讲,这本书表达了一种极有价值的东西。对软件设计领域有着独特的贡献,因为它捕获了面向对象设计的有价值的经验,并且用简洁可复用的形式表达出来。它将成为我在寻找面向对象设计思想过程中经常翻阅的一本书﹕这正是复用的真实含义所在,不是吗﹖”--sanjiv gossain, journal of object-oriented programming [/font] 目 录 序言 前言 读者指南 第1章 引言 1 1.1 什么是设计模式 2 1.2 smalltalk mvc中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象接口 9 1.6.4 描述对象的实现 10 1.6.5 运用复用机制 13 1.6.6 关联运行时刻和编译时刻的 结构 15 1.6.7 设计应支持变化 16 1.7 怎样选择设计模式 19 .1.8 怎样使用设计模式 20 第2章 实例研究:设计一个文档编 辑器 22 2.1 设计问题 23 2.2 文档结构 23 2.2.1 递归组合 24 2.2.2 图元 25 2.2.3 组合模式 27 2.3 格式化 27 2.3.1 封装格式化算法 27 2.3.2 compositor和composition 27 2.3.3 策略模式 29 2.4 修饰用户界面 29 2.4.1 透明围栏 29 2.4.2 monoglyph 30 2.4.3 decorator 模式 32 2.5 支持多种视感标准 32 2.5.1 对象创建的抽象 32 2.5.2 工厂类和产品类 33 2.5.3 abstract factory模式 35 2.6 支持多种窗口系统 35 2.6.1 我们是否可以使用abstract factory 模式 35 2.6.2 封装实现依赖关系 35 2.6.3 window和windowimp 37 2.6.4 bridge 模式 40 2.7 用户操作 40 2.7.1 封装一个请求 41 2.7.2 command 类及其子类 41 2.7.3 撤消和重做 42 2.7.4 命令历史记录 42 2.7.5 command 模式 44 2.8 拼写检查和断字处理 44 2.8.1 访问分散的信息 44 2.8.2 封装访问和遍历 45 2.8.3 iterator类及其子类 46 2.8.4 iterator模式 48 2.8.5 遍历和遍历过程中的动作 48 2.8.6 封装分析 48 2.8.7 visitor 类及其子类 51 2.8.8 visitor 模式 52 2.9 小结 53 第3章 创建型模式 54 3.1 abstract factory(抽象工厂)— 对象创建型模式 57 3.2 builder(生成器)—对象创建型 模式 63 3.3 factory method(工厂方法)— 对象创建型模式 70 3.4 prototype(原型)—对象创建型 模式 87 3.5 singleton(单件)—对象创建型 模式 84 3.6 创建型模式的讨论 89 第4章 结构型模式 91 4.1 adapter(适配器)—类对象结构型 模式 92 4.2 bridge(桥接)—对象结构型 模式 100 4.3 composite(组成)—对象结构型 模式 107 4.4 decorator(装饰)—对象结构型 模式 115 4.5 facade(外观)—对象结构型 模式 121 4.6 flyweight(享元)—对象结构型 模式 128 4.7 proxy(代理)—对象结构型 模式 137 4.8 结构型模式的讨论 144 4.8.1 adapter与bridge 144 4.8.2 composite、decorator与proxy 145 第5章 行为模式 147 5.1 chain of responsibil ity(职责链) —对象行为型模式 147 5.2 command(命令)—对象行为型 模式 154 5.3 interpreter(解释器)—类行为型 模式 162 5.4 iterator(迭代器)—对象行为型 模式 171 5.5 mediator(中介者)—对象行为型 模式 181 5.6 memento(备忘录)—对象行为型 模式 188 5.7 observer(观察者)—对象行为型 模式 194 5.8 state(状态)—对象行为型模式 201 5.9 strategy(策略)—对象行为型 模式 208 5.10 template method(模板方法) —类行为型模式 214 5.11 visitor(访问者)—对象行为型 模式 218 5.12 行为模式的讨论 228 5.12 1 封装变化 228 5.12.2 对象作为参数 228 5.12.3 通信应该被封装还是被分布 229 5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 本书简史 234 6.7 模式界 235 6.8 alexander 的模式语言 235 6.9 软件中的模式 236 6.10 邀请参与 237 6.11 临别感想 237 附录a 词汇表 238 附录b 图示符号指南 241 附录c 基本类 244 参考文献 249   前 言      本书并不是一本介绍面向对象技术或设计的书,目前已有不少好书介绍面向对象技术或设计。本书假设你至少已经比较熟悉一种面向对象编程语言,并且有一定的面向对象设计经验。当我们提及“类型”和“多态”,或“接口”继承与“实现”继承的关系时,你应该对这些概念了然于胸,而不必迫不及待地翻阅手头的字典。      另外,这也不是一篇高级专题技术论文,而是一本关于设计模式的书,它描述了在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。设计模式捕获了随时间进化与发展的问题的求解方法,因此它们并不是人们从一开始就采用的设计方案。它们反映了不为人知的重新设计和重新编码的成果,而这些都来自软件开发者为了设计出灵活可复用的软件而长时间进行的艰苦努力。设计模式捕获了这些解决方案,并用简洁易用的方式表达出来。      设计模式并不要求使用独特的语言特性,也不采用那些足以使你的朋友或老板大吃一惊的神奇的编程技巧。所有的模式均可以用标准的面向对象语言实现,这也许有时会比特殊的解法多费一些功夫,但是为了增加软件的灵活性和可复用性,多做些工作是值得的。      一旦你理解了设计模式并且有了一种“Aha!”(而不是“Huh?”)的应用经验和体验后,你将用一种非同寻常的方式思考面向对象设计。你将拥有一种深刻的洞察力,以帮助你设计出更加灵活的、模块化的、可复用的和易理解的软件—这也是你为何着迷于面向对象技术的源动力,不是吗?      当然还有一些提示和鼓励:第一次阅读此书时你可能不会完全理解它,但不必着急,我们在起初编写这本书时也没有完全理解它们!请记住,这不是一本读完一遍就可以束之高阁的书。我们希望你在软件设计过程中反复参阅此书,以获取设计灵感。      我们并不认为这组设计模式是完整的和一成不变的,它只是我们目前对设计的思考的记录。因此我们欢迎广大读者的批评与指正,无论从书中采用的实例、参考,还是我们遗漏的已知应用,或应该包含的设计模式等方面。你可以通过Addison-Wesley写信给我们,或发送电子邮件到:design-patterns@cs.uiuc.edu。你还可以发送邮件“send design pattern source”到design-patterns-source@cs.uiuc.edu获取书中的示例代码部分的源代码。      另外我们有一个专门的网页报道最新的消息与更新:      http://st-www.cs.uiuc.edu/users/patterns/DPBook/DPBook.html.      E.G. 于加州Mountain View    .  R.H. 于蒙特利尔      R.J. 于伊利诺Urbana      J.V. 于纽约 Hawthorne      1994年8月    序言    所有结构良好的面向对象软件体系结构中都包含了许多模式。实际上,当我评估一个面向对象系统的质量时,所使用的方法之一就是要判断系统的设计者是否强调了对象之间的公共协同关系。在系统开发阶段强调这种机制的优势在于,它能使所生成的系统体系结构更加精巧、简洁和易于理解,其程度远远超过了未使用模式的体系结构。    模式在构造复杂系统时的重要性早已在其他领域中被认可。特别地,Christopher Alexander和他的同事们可能最先将模式语言(pattern language)应用于城市建筑领域,他的思想和其他人的贡献已经根植于面向对象软件界。简而言之,软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。    在本书中,Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides介绍了设计模式的原理,并且对这些设计模式进行了分类描述。因此,该书做出了两个重要的贡献:首先,它展示了模式在建造复杂系统过程中所处的角色;其次,它为如何引用一组精心设计模式提供了一个实用方法,以帮助实际开发者针对特定应用问题使用适当的模式进行设计。    我曾荣幸地有机会与本书的部分作者一同进行体系结构设计工作,从他们身上我学到了许多东西,并相信通过阅读该书你同样也会受益匪浅。    Rational 软件公司首席科学家 Grady Booch

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值