大话设计模式
1、简单工厂模式:解决对象创建的问题
2、策略模式:定义算法家族,分别封装起来,让他们直接可以互相替换。此模式让算法的变化,不影响使用算法的客户。 减少耦合,简化单元测试。 封装算法,任何类型的规则,分析过程中听到需要不同时间应用不同业务规则,就可以考虑使用策略模式处理这种变化的可能性。
3、单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。 如果一个类承担的职责过多,等于把这些职责耦合在一起,一个职责的变化可能会消弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。 软件设计真正要做的许多内容,就是发现职责并把职责相互分离。如果能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责,就应该考虑类的职责分离。
4、开放-封闭原则(The Open-Closeed Principle)OCP:软件实体(类、模块、函数等等)应该可以扩展,但不可以修改。对于扩展是开放的,对于更改是封闭的。面对需求的改变却可以保持相对稳定,从而使得系统可以在第一个版本以后不断推出新的版本。 无论模块多么“封闭”,都会存在一些无法对之封闭的变化。既然不可以完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。等到变化发生时立即采取行动。 即面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有代码。我们希望的是在开发工作展开不久就知道可能发生的变化。查明可能生发的变化所等待的时间越长,要创建正确的抽象就越困难。 开放封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,可维护、可扩展、可复用、灵活性好。
5、依赖倒转原则:抽象不应该依赖细节,细节应该依赖抽象。即针对接口编程,不要对实现编程。高层模块不应该依赖底层模块,俩个都应该依赖抽象。 实现底层和高层 均可被复用。 里氏代换原则(LSP)一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它觉察不出父类对象和子类对象的区别。子类型必须能替换掉它的父类型。
6、装饰模式:动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。 装饰把类中的装饰功能从类中搬移去除,简化原有的类,有效地把类的核心职责和装饰功能分开,去除相关类中重复的装饰逻辑。 每个装饰对象的实现就和如何使用这个对象分离,每个装饰对象只关心自己的功能,不需要关心如何被添加的对象链当众。按需要有选择地、按顺序地解决“需要把所需的功能按正确的顺序串联起来进行控制”的需求。 装饰,为已有功能动态的添加更多功能的一种方式。当系统需要新功能,向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为。问题在于,这在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。
7 代理模式 为其他对象提供一种代理以控制对这个对象的访问 定义 实际执行者与代理的通用接口,这样任何用实际执行者的地方都可以用代理;代理类保存一个引用使得可以访问实体。 应用:1远程代理,为一个对象在不同的地址空间提供局部代表,隐藏一个对象存在于不同地址空间的事实。如WebService 2虚拟代理,根据需要创建开销很大的对象,通过他来存放实例化需要很长时间的真实对象。最优化性能。如浏览器一张张打开图片,未打开的图片框。 3 安全代理 ,用来控制真实对象访问时的权限, 4 智能指引,当调用真实对象时,代理处理另外一些事。 总结:在访问对象时引入一定程度的间接性,从而附加多种用途。
8 工厂模式: 简单工厂模式优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但添加新产品,需在工厂类中添加新case分支,但是违背了开放-封闭原则。 工厂模式 定义一个用于创建对象的接口,让子类决定实例化哪个类,使得一个类的实例化延迟到其子类。但把判断的问题移到了客户端代码。 工厂模式克服了简单工厂违背开放-封闭的缺点,又保持了封装对象创建过程的优点。
9 原型模式 用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。不需知道任何创建的细节,实现 ICloneable接口即可. new操作执行构造函数,若时间很长时,多次new就低效。在初始化信息不发生变化的情况下,克隆是最好的办法,这既隐藏创建细节,又提高性能。不用重新初始化对象,而是动态地获得对象运行时状态。 10 模版方法模式 既然用了继承,并且肯定继承的意义,就应该要成为子类的模版,所有重复的代码都应该上升到父类去。 当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模版方法模式来处理。 模版方法:定义一个操作中的算法骨架,将一些步骤延迟到子类中,这样使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。 特点:通过把不变的行为搬移到超类,去除子类中的重复代码来体现他的优势,以便很好的实现代码复用。
11 迪米特法则 LoD 最少知识原则 如果俩个类不必彼此直接通信,那么这俩个类就不应当发生直接的相互作用。如果其中一个需要调用另一个的某方法,可以通过第三者转发这个调用 强调 1类尽量降低成员的访问权限,2类之间的松耦合
12 外观模式 Facade(解耦) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,使得这一子系统更加容易使用。 何时用: 设计初期 有意识的将不同的俩个层分离——三层架构,层层之间建立外观; 开发阶段 子系统往往因为不断重构演化而复杂,使用外观,提供一个简单的接口,减少依赖; 维护遗留大型系统 对难以维护和扩展的,用外观,提供设计粗糙或高度复杂的遗留代码的较清晰简单接口,让新系统与facade交互。
13 建造者模式 Builder 讲一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示.(生成器模式) 主要用于创建一些复杂对象,这些对象内部构建间的 建造顺序稳定,却面临复杂变化.
14 观察者模式 定义一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象.当主题发生变化时,通知所以观察者,使他们能够自动更新自己.
~15抽象工厂模式 Abstract Factory 提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类 优缺点: 易于交换产品系列,具体工厂类在一个应用中只需要初始化一次,让具体的创建实例与客户端分离.实现复杂 16 状态模式 State一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。——当控制一个对象状态转换时的条件表达式过去复杂的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,。 将与 特定状态相关的行为局部化,并且将不同状态行为分割开来。 将 特定状态相关的行为放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新状态和转换。消除庞大的条件分支,把各种状态转移逻辑分布到State的子类之间,减少相互依赖。 当一个对象的行为取决于他的状态,并且在运行时刻根据状态改变行为时。
17 适配器模式 Adapter 将一个类的接口转换成客户端希望的另外一个接口,使得原本由于不兼容而不能一起工作的那些类可以一起工作。 系统的数据和行为都正确,接口不符,用适配器,使控制范围之外的一个原有对象与某个接口匹配。用于复用一些现存的类。 在后期维护时使用,前期尽量设计好不用适配器。当双方都不太容易修改时再使用。
18 备忘录模式 Memento 不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以后可以将该对象恢复到原先保存的状态。 要保存的细节给封装在Memento中,适用于功能较复杂的,但需要维护或记录属性历史的类,或者要保存的属性只是众多属性的一小部分时。 如使用命令模式,需实现命令的撤销功能,那么命令模式可以使用备忘录模式才存储可撤销操作的状态。
19 组合模式 整体与部分可以被一致对待的问题 Composite将对象组合成树形结构以表示 部分-整体 的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 需求中体现部分与整体层次结构,希望用户可以忽略组合对象与单对象的不同,统一地使用组合结构中的所有对象。 20 迭代器模式 Iterator 提供一种方法顺序访问一个聚合对象中的各元素,而又不暴露该对象的内部表示。
21 单例模式 Singleton 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 C#与公共语言运行库提供一种 静态初始化 方法,不需要开发人员显式编写线程安全代码,即可解决多线程下不安全的问题。——静态初始化在被加载时就实例化,饿汉式单例。在第一次被引用时才实例化,懒汉式单例。
22 桥接模式 继承:对象的继承关系在编译时定义好了,无法在运行时改变从父类继承的实现。子类的实现与他的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当要复用子类时,如果继承下来的实现不适合解决新问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。 合成/聚合复用原则(CARP),尽量使用合成/聚合,尽量不要使用类继承 聚合 弱拥有,A包含B,但B不是A的一部分; 合成 强拥有,严格的部分和整体的关系; 优先使用对象的合成/聚合 将有助于你保持每个类被封装,并被集中在单个任务上,这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的。 桥接模式Bridge 将抽象部分与它的实现部分分离,使他们都可以独立的变化。 实现系统可能有多角度分类,每种分类都有可能变化,那么就就多角度分离出来让他们独立变化,减少耦合。
23 命令模式 行为请求者 与 行为实现着紧耦合,对请求排队或记录请求日志,以及支持可撤销的操作时,不适合。 Command 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对;请求排队或记录日志,以及支持可撤销操作 优点: 较容易地设计一个命令队列;较容易的将命令记入日志;允许接收请求的一方决定是否要否决请求;容易实现对请求的撤销和重做;加进新的具体命令类不影响其他类,扩展容易;把请求一个操作的对象与执行操作的对象分隔开。 敏捷开发原则:不为代码添加基于猜测的、实际不需要的功能。
24 职责链模式 Chain of Responsibility 使多个对象都有机会处理请求,避免请求发送者和接收者耦合关系。将这些个对象连接成一条链,沿链传递请求,直到有对象处理为止。 好处:接收者和发送者没有对方明确信息,链中对象自己也不知道链结构,简化对象的相互连接,仅需要保持一个指向其后继的引用;方便增加和修改处理请求的结构,给对象指派职责灵活
25 中介者模式 Mediator 用一个中介对象来封装一系列对象交互。各对象不显式引用,解耦,较容易改变之间的交互。 大量的连接使得对象不可能在没其他对象的支持下工作,系统表现为不可分割的整体,造成复用困难. 当系统出现 多对多 交互复杂的对象群时,先反思设计是否合理,再考虑中介者;由于对对象如何协作进行了抽象,将中介作为独立的概念封装,这样关注点从对象本身转移到他们之间的交互,可以站在更宏观的角度去看待系统。缺点:控制集中化,交互复杂性变为中介者的复杂性。应用于一组对象以定义良好但复杂的方式进行通信的场合,以及想定制一个分布在多个类中的行为,又不想生成太多子类的场合。
~26 享元模式 Flyweight 运用共享技术有效地支持大量细粒度的对象
~27 解释器模式 interpreter 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。构建一个解释器该解释器通过解释这些句子来解决该问题。 一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。容易改变和扩展文法,使用类来表示文法规则,可使用继承来改变或扩展文法。容易实现文法,定义抽象语法树中各个接点的类的实现大体类似,这些类都易于直接编写。 不足:为文法中的每条规则至少定义一个类,因此包含许多规则的文法可能难以管理和维护。当文法非常复杂时,使用其他技术如语法分析程序或编译器生成器来处理。
28 访问者模式 Visitor 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 访问模式适用于数据结构相对稳定的系统;把数据结构和作用于结构上的操作之间的耦合解开,使得操作集合可以相对自由地演化。 目的 把处理从数据结构分离出来。在稳定的数据结构和变化的算法的话,访问者模式比较适合,它使得算法操作变得容易。易于增加新操作,缺点是增加新数据结构困难。
29总结篇
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
对设计模式的学习,暂告一段落。其中 抽象工厂/享元/解释器 不太理解。当然大多数是简单理解也未曾使用过,没什么深刻印象。这些都留待以后工作遇到实际问题再细细钻研吧。程序本来就是灵活的,不拘于模式,写程序的人更不应生搬硬套。有合适的就用,用的多了自然能组合和变化,无招胜有招。
结语:我只想把我所知道的,尽量简洁清楚地表达出来。