ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 设计模式(Design pattern) 设计模式该术语源自Erich Gamma等人在上世纪90年代从建筑设计领域引入到计算机科学的(很难想象到底有多大关联)。它是对软件设计中一些反复出现,普遍存在的问题所提出的解决方案。所以说设计模式并不是某种语言的某块代码,设计模式是一种思想,提供给在编码时候遇到的各种问题是可以采取的解决方案,更倾向于一种逻辑思维,而不是万能代码块。 设计模式使人可以更加简单方便的复用一些较为成功的设计和体系结构,使用设计模式来使人理解整个系统的开发思路。 ## 设计模式的四要素 **模式名称(pattern name)**:助记名,以几个词来描述问题,解决方案和效果。模式名可以帮助我们思考,一边与其他程序员进行设计思想交流。 **问题(problem)**:描绘使用设计模式的具体情况。解释设计问题和问题存在的因果,可能描述特定的设计问题,也可能描述导致不灵活的设计的类或者对象结构等。 **解决方案(solution)**:描述设计的组成成分,它们之间的相互关系与各自的职责和协作方式。解决方案并不具体的描述某种设计的实现,而是提供设计问题的抽象描述和怎样用一些一般意义的元素来解决这个问题。 **效果(consequences)**:描述模式的应用效果以及使用模式需要权衡的问题,虽然很少提到模式的效果,但是对于评价该模式在该问题下是有很重要的意义。模式效果包括此模式对于系统的灵活性,扩充性或者可移植性的影响,显示列出这些效果可以客观的评价该模式对于该问题的适用性。 ## 设计模式分类 **创建型模式**:单例模式,抽象工厂模式,建造者模式,工厂模式与原型模式。 **结构型模式**:适配器模式,桥接模式,装饰者模式,组合模式,外观模式,享元模式以及代理模式。 **行为型模式**:模板方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,职责链模式和访问者模式。 ## 23种设计模式 以下概述主要来源于网络资料,定义方面的的东西不需要过多记忆,但需要了解,才能更好的理解为什么要使用它。虽然说是来源于网络,但都是手工码字,这样会让记忆更加深刻。 ### 抽象工厂模式(Abstract Factory) 客户类与工厂类分开,当客户需要某种产品时向对应工厂发出请求。缺点是当产品需要修改时,工厂类也需要做相应的修改。 **意图** 提供一个创建一系列相关或者相互依赖的对象接口,无需指定它们具体的类。 **适用性** 一个系统要独立于它的产品创建,组合的时候。 一个系统要由多个产品系列中的一个来配置的时候。 强调一系列相关产品对象设计以便进行联合使用时。 对于一个产品库,只想显示接口而不是具体的实现的时候。 ### 工厂方法模式(Factory Method) 其核心工厂类不再负责所有的产品撞见,而是将具体工作委托给子类,自身成为一个抽象的工厂角色,仅负责给出工厂类必须实现的接口,而不需要关系具体哪种产品被实例化的细节。 **意图** 定义一个用于创建对象接口,让子类来决定实例化哪一个类,将类的实例化延迟到其子类。 **适用性** 当一个类不知道它所必须创建的对象的类的时候。 当一个类希望由其子类来创建对象的时候。 ### 建造者模式(Builder) 将对象的内部表象和对象的生产过程分割开来,从而使得一个建造过程具有不同内部表象的产品对象。建造模式使得产品内部表象可以独立出来变化,客户不需要知道内部细节,可以强制实行一种分步建造过程。 **意图** 将一个复杂的对象的构建与它的表现分离,使同样的构建形式可以得到不同的表示。 **适用性** 将复杂对象的算法需要独立于对象的组成部分以及装配方式的时候。 构造过程允许构造不同的对象表示。 ### 适配器模式(Adapter) 将一个类的接口变为客户端所希望的接口类型,从而使原先因接口不匹配而无法工作的两个类可以一起工作。 **意图** 将某个接口改装变为所需要类型的接口,也可以是原本不兼容的接口适配成兼容。 **适用性** 希望使用一个已经存在的类,但是与你所需要的接口有些不吻合时。 希望创建一个可以复用的类,可以与其他已存在或者未存在的类进行协同工作。 ### 桥接模式(Bridge) 将抽象画和实例化解耦,使得两者可以独立变化。即降低耦合度。也就是说将抽象化和实例化之间的关系使用组合/聚合的关系而非继承关系,两者可以独立的变化。 **意图** 将抽象部分与它的实现部分分离,使它们可以独立的变化。 **适用性** 在对于抽象部分和实现部分不希望使用固定的关系。 类的抽象和类的实现都应该都应该可以可以通过生成子类的方式来加以扩充。 对一个抽象的实现部分的修改应对客户不产生影响。 希望在多个对象之间共享(比如使用引用计数),但是客户不知道该点。 ### 职责链模式(Chain of Responsibility) 在职责链模式中,很多对象由每一个对象对其下家的引用而连接起来的一条链。请求在这个链上进行传递直到链上的某一个对象决定处理该请求。对于链上的每一个对象成为处理者,处理者有两个选择:承担处理责任挥着将请求传递给下家,请求可以不被任何对象处理。 **意图** 使多个对象都有机会处理请求,从而避免请求发送者和接受者之间的耦合关系。将这些对象连成一条链,并且沿着该链传输,直到有对象对他进行处理。 **适用性** 有对个对象可以处理一个请求,具体是哪个对象处理会在运行时自动确定。 在不明确接受者情况下,向多个对象提交一个请求。 可以动态的指定那个对象集。 ### 命令模式(Command) 命令模式将一个请求或者操作封装到一个对象中。命令模式将发出命令和执行命令的责任分割开,委派给不同的对象。命令模式也允许请求方个接受方相互独立,使得请求方不需要知道接收方的接口等。 **意图** 将一个请求封装为一个对象,从而可以使你应不同的请求对客户进行参数化。对于一些排队的请求可以进行取消操作。 **适用性** 抽象出待执行的动作以参数化某对象可以使用回调表达这种参数化机制。 在不同的时刻指定,排列和执行请求。一个 command 对象可以有一个与初始请求无关的生存期。 支持对于取消,修改操作。 用构建在原语上的高层操作构造一个系统,一个事务封装了对数据的一组变动,Command模式提供了对事务进行建模的方法,有一个公共的接口,使得可以使用同一种方式来调用所有的事务。也易于添加新事务以扩展系统。 ### 组合模式(Composite) 组合模式间对象组织到树结构中,可以用来描述整体和部分的关系。组合模式就是一个处理对象的树结构的模式。 **意图** 将对象组合成树形结构以表示“部分 - 整体”的层次关系,使用户对于单个对象和组合对象使用具有一致性。 **适用性** 对于对象希望表现出 部分 - 整体 的层次结构。 希望统一使用组合结构中的所有对象。 ### 装饰者模式(Decorator) 装饰者模式以对客户端透明的方式来扩展对象功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给对象添加功能,这些功能也能动态撤销。常用于对增加一些基本功能的排列组合而产生的非常大量的功能。 **意图** 动态的给一个对象添加一些额外的职责。就增加功能来说,装饰者模式比生成子类更为灵活。 **适用性** 在不影响其他的对象情况下,以动态,透明的方式给单个兑现添加职责。 当无法使用类似生成子类的方式进行类的拓展的时候。如有大量的独立应用,为支持各种组合那么将出现数量级爆炸的情况,或者类定义被隐藏等不能用于生成子类。 ### 外观模式(Facade 门面模式) 外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个更高级的接口使得子系统更容易使用。每一个子系统只有一个门面模式,此门面模式只有一个实例,即单例模式。整个系统中可以有多种门面类。 **意图** 为子类系统中的一组接口提供一致的界面,外观模式定义一个高级接口以便子类更容易的调用。 **适用性** 当需要为一个非常复杂的子类系统提供一个简单的接口的时候。 外观模式提供一个简单的缺省视图,这一视图对大多数用户来说已经OK,而对高级用户可以绕过外观层进行所需要的处理。 ### 享元模式(Flyweight) 享元模式以共享的方式高效的支持大量细粒度对象。共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部不会随环境的改变而有所不同。外蕴状态就是随环境的改变而变化的。两者相互独立互不影响。将可以共享的状态和非共享的状态从常规类里面区分出来。客户不可以直接创建共享对象,应当使用一个工厂对象负责创建共享的对象。享元模式可以大幅度的降低内存中对象的数量。 **意图** 运用共享技术有效地支持大量细粒度的对象。 **适用性** 一个程序中使用了大量的对象。 由于对象数量造成了大量存储开销。 大多对象的状态可以变为外部的状态 可以使用较少的共享对象来进行处理。 ### 解析器模式(Interpreter) 给定一个语言后,解析器模式可以定义出其文法的表示,并提供一个解析器。客户端可以使用这个解析器来解析该语言中的语句。解析器模式将描述怎样再有了一个简单的文法后使用模式设计解析这些语句。该语言是指任何解析器对象能够解释的任何组合。在解析器模式中需要定义一个代表文法的命令类的等级结构,每一个命令都有一个对应的解释。 **意图** 给定一种语言,定义文法表示,并且在定义一个解析器来转化该语言。 **适用性** 简化文法所需要的逻辑处理,文法简单。 ### 迭代器模式(Iterator) 迭代器模式可以顺序访问一个聚集中的元素而不必暴露内部表象。多个对象聚集在一起形成的整体称之为聚集,聚集对象则是包含一组对象的容器。迭代模式将迭代逻辑封装到一个独立的对象中,与本身的聚集对象分离开来。迭代模式简化了聚集的逻辑思想,将行为独立分割开来方便调整修改替换。所以迭代算法可以独立于聚集对象进行变化。 **意图** 提供一个方法顺序访问一个聚合对象中的各个元素而又不暴露该对象的内部表示。 **适用性** 访问聚合对象,而不希望内部暴露。 支持对于聚合对象的多种遍历。 为遍历各种对象提供统一的接口。 ### 中介者模式(Mediator) 中介者模式包装了一系列对象相互作用的方式,使得这些对象不必相互有明显的联系。使耦合变得松散。当某些对象发生改变的时候也不会影响其他的对象之间的作用,保证各个对象之间的作用相互独立,这边并不是对象与对象之间,而是作用与作用之间的联系变得独立开。中介者模式将多对多的相互作用转化为一对多的相互作用,将对象的行为和协作抽象画,把对象的一些小行为与其他对象的相互作用分开处理。 **意图** 使用中介者来封装一系列的对象之间的交互,不显示的表示各个对象的相互引用关系,降低对象之间的耦合度。 **适用性** 定义良好的一组对象需要很复杂的通信方式。从而产生的相互依赖关系但以理解。 一个对象直接对其他很多对象进行通信导致了难以复用该对象。 需要定制一个分布在各个类中的行为又不想生成太多子类。 ### 备忘录模式(Memento) 备忘录对象是一个用来存储另外一个对象内部状态的快照对象,在意在不破坏对象封装的前提下将一个对象的状态捕捉到,存储在外部以便可以随时观察记录,以便将来可以还原到某一个状态。 **意图** 在不破坏封装性的前提下捕获一个对象的内部状态并将该状态保存在对象之外来标记。 **适用性** 需要注意必须保持对象的某一时刻状态并且不对对象造成封装性的破坏,不制造多余的暴露接口。 ### 观察者模式(Observer) 观察者模式定义一种一对多的状态,让多个观察者同时监听某一个对象。这个对象主题发生变化的时候会告知所有的观察者对象,使它们自动更新自己。 **意图** 定义对象间的一种一对多的依赖关系,当一个对象发生改变的时候,所有依赖于该对象的其他对象都将得到通知,并且被自动更新。 **适用性** 当抽象模型具有两个方面,其中一个方面依赖于另一个方面,将这两者分开封装在独立的对象中使得他们可以独立改变以及复用。 当一个对象在改变的时候需要同时改变其他对象,并且这个对象集合有可能会改变。并且不能假定这些对象来增加耦合度。 ### 原型模式(Prototype) 通过给出一个原型对象来指明所要创建的对象类型,复用这个原型对象来创建出个更多的同类型对象。原型模式允许动态的增加或者减少产品类,可以不需要任何的等级结构,原型模式适用于任何结构。 **意图** 用原型实例来指定对象创建的种类,并且通过拷贝这些原型来创建新的对象。 **适用性** 需要实例化的类在运行时候指定。(对于前端的JSer来说,这是最熟悉不过的了) ### 代理模式(proxy) 代理模式给某一个对象提供一个代理对象,并由代理对象控制对象源对象的引用。在某些情况下客户不想活着不能够直接引用一个人对象,代理对象在客户和目标对象中起到中介者的作用,代理对象可以仅仅只有一个被代理的接口,这时候代理对象不能创建被代理的对象,被代理的对象必须由系统的其他角色代为创建和传入。 **意图** 为其他对象提供一种代理来来控制对于某个特定对象的访问或者处理。 **适用性** 在需要使用比较爱通用和复杂的对象指针来代替简单指针的时候。 ### 单例模式(Singleton) 单例模式确保每一个类只有一个实例,而且自行的实例化并且想整个系统提供该实例的接口。单例模式只有在真正需要单一模式的时候使用。 **结构** 保证一个类只有一个实例,并提供一个访问它的全局访问点。 **适用性** 当类只能有一个实例,客户端通过规范的访问点来进行访问。 ### 状态模式(state) 状态模式允许一个对象在其内部状态改变的时候改变行为。使得看上去和改变了类是一样的。状态模式将所研究的对象的行为包装在不同的对象里,每一个状态都属于一个抽象状态类的一个子类。状态模式需要对每一个系统可能取得的状态创建一个状态类的子类。当系统的状态发生变化的时候,系统便改变所选的子类。 **意图** 允许一个对象在其内部状态改变的时候改变行为。 **适用性** 一个对象的行为取决于它的状态,并且必须在运行时刻根据状态来改变行为。 ### 策略模式(Strategy) 策略模式针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响客户端的情况下发生变化。将行为与环境分开。环境类负责维持和查询行为类,各个算法在具体的策略类中提供。所以算法的增减不会影响环境和客户端。 **意图** 定义一系列算法进行单独封装,并且是它们可以相互替换,使算法独立于客户变化而变化。 **适用性** 许多相关的类,仅仅是行为上有所差别,策略模式可以实现在多个行为中选取一个来配置一个类。 ### 模板方法模式(Template Method) 模板方法模式准备一个抽象类,将部分逻辑以及具体方法以构造子类的方式实现,然后声明一些抽象方法来事子类实现剩余的逻辑。不同的子类可以以不同的方式来实现这些抽象方法,从而对剩余逻辑的实现。先定制一个顶级的逻辑框架,而将逻辑的细节刘诶具体的子类去实现。 **意图** 定义一个算法骨架,将一些步骤延迟到子类中,使子类可以不改变一个算法结构却可以重新定义算法的步骤。 **适用性** 一次性实现算法的不变部分,将可变部分留在子类中实现。 一个类定义多种行为,并且这些行为在这个类中的操作是以多个条件语句的形式出现。 ### 访问者模式(Visitor) 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦操作需要做修改,接受设个操作的数据结构可以保持不变。适用于数据结构相对未定的系统,将数据结构和作用于结构上的操作耦合解脱开使得操作可以相对自由的演化。访问者模式使得增加新的操作变得更为容易。访问者模式将有关的行为集中到一个访问者对象中,而不是分散在一个个环节节点中。当使用访问者模式的时候要将尽可能多的对象浏览逻辑放在访问者类中,而不是子类中。 **意图** 表示一个作用于某个对象结构中的各元素的操作,使你可以在不改变各个元素的类的情况下定义作用于这些元素的新的操作。 **适用性** 一个对象结构中包含多个类对象,具有不同的接口,而你希望对这些对象实施一些依赖于具体某个类的操作。 需要对一个对象结构中的对象进行很多不同的并且不想关的操作,这些操作需要避免污染对象。访问者模式可以将相关的操作集中放入一个类中,被对象结构所共享,从而对象结构中的每个子对象都可以被共享到。 # 参考资料 [Hi~颖峰!的博客](http://blog.chinaunix.net/uid-26672038-id-4067551.html)