项目开发中发现问题、解决问题这个过程当中会出现不少问题,好比重复出现、某个问题的遗留,这些问题的本质就是设计模式。今天记录设计模式的知识点。html
在java以及其余的面向对象设计模式中,类与类之间主要有6种关系,他们分别是:依赖、关联、聚合、组合、继承、实现。它们的耦合度依次加强。
依赖关系:
对于两个相对独立的对象,当一个对象负责构造另外一个对象的实例,或者依赖另外一个对象的服务时,这两个对象之间主要体现为依赖关系。
关联关系:
分为单向关联和双向关联。在java中,单向关联表现为:类A当中使用了类B,其中类B是做为类A的成员变量。双向关联表现为:类A当中使用了类B做为成员变量;同时类B中也使用了类A做为成员变量。
聚合关系:
是关联关系的一种,耦合度强于关联,他们的代码表现是相同的,仅仅是在语义上有所区别:关联关系的对象间是相互独立的,而聚合关系的对象之间存在着包容关系,他们之间是“总体-个体”的相互关系。
组合关系:
是一种耦合度更强的关联关系。存在组合关系的类表示“总体-部分”的关联关系,“总体”负责“部分”的生命周期,他们之间是共生共死的;而且“部分”单独存在时没有任何意义。
继承:
表示类与类(或者接口与接口)之间的父子关系。
实现:
表示一个类实现一个或多个接口的方法。java
设计原则android
要点 | 定义 | 描述 |
单一职责原则 | 不要存在多于一个致使类变动的缘由。通俗的说,即一个类只负责一项职责。 | 问题由来:类T负责两个不一样的职责:职责P1,职责P2。当因为职责P1需求发生改变而须要修改类T时,有可能会致使本来运行正常的职责P2功能发生故障。 解决方案:遵循单一职责原则。分别创建两个类T一、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。 |
里氏替换原则 | 定义1:若是对每个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的全部程序 P 在全部的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。 定义2:全部引用基类的地方必须能透明地使用其子类的对象。 |
问题由来:有一功能P1,由类A完成。现须要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。新功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会致使原有功能P1发生故障。 解决方案:当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能P2外,尽可能不要重写父类A的方法,也尽可能不要重载父类A的方法。 |
依赖倒置原则 | 高层模块不该该依赖低层模块,两者都应该依赖其抽象;抽象不该该依赖细节;细节应该依赖抽象。 | 问题由来:类A直接依赖类B,假如要将类A改成依赖类C,则必须经过修改类A的代码来达成。这种场景下,类A通常是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操做;假如修改类A,会给程序带来没必要要的风险。 解决方案:将类A修改成依赖接口I,类B和类C各自实现接口I,类A经过接口I间接与类B或者类C发生联系,则会大大下降修改类A的概率。 |
接口隔离原则 | 客户端不该该依赖它不须要的接口;一个类对另外一个类的依赖应该创建在最小的接口上。 | 问题由来:类A经过接口I依赖类B,类C经过接口I依赖类D,若是接口I对于类A和类B来讲不是最小接口,则类B和类D必须去实现他们不须要的方法。 解决方案:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们须要的接口创建依赖关系。也就是采用接口隔离原则。 |
迪米特法则 | 一个对象应该对其余对象保持最少的了解。 | 问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另外一个类的影响也越大。 解决方案:尽可能下降类与类之间的耦合。 |
开闭原则 | 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。 | 问题由来:在软件的生命周期内,由于变化、升级和维护等缘由须要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使咱们不得不对整个功能进行重构,而且须要原有代码通过从新测试。 解决方案:当软件须要变化时,尽可能经过扩展软件实体的行为来实现变化,而不是经过修改已有的代码来实现变化。 |
设计模式程序员
要点 | 定义 | 描述 |
单例模式 | 确保一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。 | 单例模式注意事项: 只能使用单例类提供的方法获得单例对象,不要使用反射,不然将会实例化一个新对象。不要作断开单例类对象与类中静态引用的危险操做。多线程使用单例使用共享资源时,注意线程安全问题。 |
工厂方法模式 | 定义一个用于建立对象的接口,让子类决定实例化哪个类,工厂方法使一个类的实例化延迟到其子类。 | 在工厂方法模式中,核心的工厂类再也不负责全部的对象的建立,而是将具体建立的工做交给子类去作。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪个类应当被实例化这种细节。 |
抽象工厂模式 | 为建立一组相关或相互依赖的对象提供一个接口,并且无需指定他们的具体类。 | 在如下状况下,适用于工厂方法模式: (1) 当一个类不知道它所必须建立的对象的类的时候。 (2) 当一个类但愿由它的子类来指定它所建立的对象的时候。 (3) 当类将建立对象的职责委托给多个帮助子类中的某一个,而且你但愿将哪个帮助子类是代理者这一信息局部化的时候。 |
模版方法模式 | 定义一个操做中算法的框架,而将一些步骤延迟到子类中,使得子类能够不改变算法的结构便可重定义该算法中的某些特定步骤。 | 子类能够置换掉父类的可变部分,可是子类却不能够改变模板方法所表明的顶级逻辑。 每当定义一个新的子类时,不要按照控制流程的思路去想,而应当按照“责任”的思路去想。换言之,应当考虑哪些操做是必须置换掉的,哪些操做是能够置换掉的,以及哪些操做是不能够置换掉的。使用模板模式可使这些责任变得清晰。 |
建造者模式 | 将一个复杂对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的表示。 | 与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后获得产品。即建造模式能够强制实行一种分步骤进行的建造过程。 建造模式是将复杂的内部建立封装在内部,对于外部调用的人来讲,只须要传入建造者和建造工具,对于内部是如何建形成成品的,调用者无需关心。 在Java的应用中JavaMail使用到了该模式。 |
代理模式 | 为其余对象提供一种代理以控制对这个对象的访问。 | 所谓代理,就是一我的或者机构表明另外一我的或者机构采起行动。在一些状况下,一个客户不想或者不可以直接引用一个对象,而代理对象能够在客户端和目标对象之间起到中介的做用。 |
原型模式 | 用原型实例指定建立对象的种类,并经过拷贝这些原型建立新的对象。 原型模式要求对象实现一个能够“克隆”自身的接口,这样就能够经过复制一个实例对象自己来建立一个新的实例。这样一来,经过原型实例建立新的对象,就再也不须要关心这个实例自己的类型,只要实现了克隆自身的方法,就能够经过这个方法来获取新的对象,而无须再去经过new来建立。 |
在Java语言里深度克隆一个对象,经常能够先使对象实现Serializable接口,而后把对象(实际上只是对象的拷贝)写到一个流里(序列化),再从流里读回来(反序列化),即可以重建对象。 原型模式的优势 原型模式容许在运行时动态改变具体的实现类型。原型模式能够在运行期间,由客户来注册符合原型接口的实现类型,也能够动态地改变具体的实现类型,看起来接口没有任何变化,但其实运行的已是另一个类实例了。由于克隆一个原型就相似于实例化一个类。 原型模式的缺点 原型模式最主要的缺点是每个类都必须配备一个克隆方法。配备克隆方法须要对类的功能进行通盘考虑,这对于全新的类来讲不是很难,而对于已经有的类不必定很容易,特别是当一个类引用不支持序列化的间接对象,或者引用含有循环结构的时候。 |
中介者模式 | 用一个中介者对象封装一系列的对象交互,中介者使各对象不须要显示地相互做用,从而使耦合松散,并且能够独立地改变它们之间的交互。 中介者模式的优势 适当地使用中介者模式能够避免同事类之间的过分耦合,使得各同事类之间能够相对独立地使用。 使用中介者模式能够将对象间一对多的关联转变为一对一的关联,使对象间的关系易于理解和维护。 使用中介者模式能够将对象的行为和协做进行抽象,可以比较灵活的处理对象间的相互做用。 |
适用场景 在面向对象编程中,一个类必然会与其余的类发生依赖关系,彻底独立的类是没有意义的。一个类同时依赖多个类的状况也至关广泛,既然存在这样的状况,说明,一对多的依赖关系有它的合理性,适当的使用中介者模式可使本来凌乱的对象关系清晰,可是若是滥用,则可能会带来反的效果。通常来讲,只有对于那种同事类之间是网状结构的关系,才会考虑使用中介者模式。能够将网状结构变为星状结构,使同事类之间的关系变的清晰一些。 中介者模式是一种比较经常使用的模式,也是一种比较容易被滥用的模式。对于大多数的状况,同事类之间的关系不会复杂到混乱不堪的网状结构,所以,大多数状况下,将对象间的依赖关系封装的同事类内部就能够的,没有必要非引入中介者模式。滥用中介者模式,只会让事情变的更复杂。 |
命令模式 | 意图:将一个请求封装为一个对象,从而可用不一样的请求对客户进行参数化;对请求排队或记录日志,以及支持可撤销的操做 动机:将”发出请求的对象”和”接收与执行这些请求的对象”分隔开来。 |
常见应用: 一、工做队列,线程池,日程安排 二、日志请求(系统恢复) 要点: 一、命令模式将发出请求的对象和执行请求的对象解耦 二、在被解耦的二者之间是经过命令对象进行沟通的。命令对象封装了接收者和一个或一组动做 三、调用者经过调用命令对象的execute()发出请求,这会使得接收者的动做被调用 四、调用者能够接受命令看成参数,甚至在运行时动态的进行 五、命令能够支持撤销,作法是实现一个undo()方法来回到execute()被执行前的状态 六、宏命令是命令的一种简单的延伸,容许调用多个命令。宏方法也能够支持撤销 七、实际操做时,很常见使用"聪明"命令对象,也就是直接实现了请求,而不是将工做委托给接受者(弊端?) 八、命令也能够用来实现日志和事物系统 |
责任链模式 | 使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。 | 一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,而是把责任推给下家。不容许出现某一个具体处理者对象在承担了一部分责任后又 把责任向下传的状况。 在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求能够最终不被任何接收端对象所接收。 纯的责任链模式的实际例子很难找到,通常看到的例子均是不纯的责任链模式的实现。有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的。可是在实际的系统里,纯的责任链很难找到。若是坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。 |
装饰模式 | 又名包装(Wrapper)模式,装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。 | 装饰模式与类继承的区别: 1) 装饰模式是一种动态行为,对已经存在类进行随意组合,而类的继承是一种静态的行为,一个类定义成什么样的,该类的对象便具备什么样的功能,没法动态的改变。 2) 装饰模式扩展的是对象的功能,不须要增长类的数量,而类继承扩展是类的功能,在继承的关系中,若是咱们想增长一个对象的功能,咱们只能经过继承关系,在子类中增长两个方法。 3) 装饰与继承比较图: 4) 装饰模式是在不改变原类文件和使用继承的状况下,动态的扩展一个对象的功能,它是经过建立一个包装对象,也就是装饰来包裹真是的对象。 5. 装饰模式把对客户端的调用委派给被装饰的类,装饰模式的关键在于这种扩展彻底透明的。 |
策略模式 | 定义一组算法,将每一个算法都封装起来,而且使他们之间能够互换。 策略模式的好处在于你能够动态的改变对象的行为。 |
策略模式属于对象行为型模式,主要针对一组算法,将每个算法封装到具备共同接口的独立的类中,从而使得它们能够相互替换。策略模式使得算法能够在不影响 到客户端的状况下发生变化。一般,策略模式适用于当一个应用程序须要实现一种特定的服务或者功能,并且该程序有多种实现方式时使用。 |
适配器模式 | 基于现有类所提供的服务,向客户提供接口,以知足客户的指望。 适配器模式的用意是要改变源的接口,以便于目标接口相容。缺省适配的用意稍有不一样,它是为了方便创建一个不平庸的适配器类而提供的一种平庸实现。 |
适配器模式的优势 更好的复用性 系统须要使用现有的类,而此类的接口不符合系统的须要。那么经过适配器模式就可让这些功能获得更好的复用。 更好的扩展性 在实现适配器功能的时候,能够调用本身开发的功能,从而天然地扩展系统的功能。 适配器模式的缺点 过多的使用适配器,会让系统很是零乱,不易总体进行把握。好比,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统若是太多出现这种状况,无异于一场灾难。所以若是不是颇有必要,能够不使用适配器,而是直接对系统进行重构。 |
迭代器模式 | 提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。 | 在jdk中,与迭代器相关的接口有两个:Iterator 与 Iterable Iterator:迭代器,Iterator及其子类一般是迭代器自己的结构与方法; Iterable:可迭代的,那些想用到迭代器功能的其它类,如AbstractList HashMap等,须要实现该接口。 |
组合模式 | 将对象组合成树形结构以表示‘部分-总体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具备一致性。 对象经过实现(继承)统一的接口(抽象类),调用者对单一对象和组合对象的操做具备一致性。 |
经过实现组合模式,调用者对组合对象的操做与对单一对象的操做具备一致性。调用者不用关心这是组合对象仍是文件,也不用关心组合对象内部的具体结构,就能够调用相关方法,实现功能。 |
观察者模式 | 定义对象间一种一对多的依赖关系,使得当每个对象改变状态,则全部依赖于它的对象都会获得通知并自动更新。 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知全部观察者对象,使它们可以自动更新本身。 |
在JAVA语言的java.util库里面,提供了一个Observable类以及一个Observer接口,构成JAVA语言对观察者模式的支持。 |
门面模式 | 外部与一个子系统的通讯必须经过一个统一的门面对象进行。 | 门面模式的优势: ● 松散耦合 门面模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。 ● 简单易用 门面模式让子系统更加易用,客户端再也不须要了解子系统内部的实现,也不须要跟众多子系统内部的模块进行交互,只须要跟门面类交互就能够了。 ● 更好的划分访问层次 经过合理使用Facade,能够帮助咱们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把须要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。 |
备忘录模式 | 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象以外保存这个状态。这样就能够将该对象恢复到原先保存的状态。 | 备忘录对象是一个用来存储另一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而能够在未来合适的时候把这个对象还原到存储起来的状态。备忘录模式经常与命令模式和迭代子模式一同使用。 |
访问者模式 | 封装某些做用于某种数据结构中各元素的操做,它能够在不改变数据结构的前提下定义做用于这些元素的新的操做。 访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操做。一旦这些操做须要修改的话,接受这个操做的数据结构则能够保持不变。 |
访问者模式的优势 好的扩展性 可以在不修改对象结构中的元素的状况下,为对象结构中的元素添加新的功能。 好的复用性 能够经过访问者来定义整个对象结构通用的功能,从而提升复用程度。 分离无关行为 能够经过访问者来分离无关的行为,把相关的行为封装在一块儿,构成一个访问者,这样每个访问者的功能都比较单一。 访问者模式的缺点 对象结构变化很困难 不适用于对象结构中的类常常变化的状况,由于对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价过高。 破坏封装 访问者模式一般须要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。 |
状态模式 | 当一个对象的内在状态改变时容许改变其行为,这个对象看起来像是改变了其类。 状态模式容许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类同样。 |
|
解释器模式 | 给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。 | |
享元模式 | 复用咱们内存中已存在的对象,下降系统建立对象实例的性能消耗。 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是由于这样更能反映模式的用意。享元模式是对象的结构模式。享元模式以共享的方式高效地支持大量的细粒度对象。 |
享元模式采用一个共享来避免大量拥有相同内容对象的开销。这种开销最多见、最直观的就是内存的损耗。享元对象能作到共享的关键是区份内蕴状态(Internal State)和外蕴状态(External State)。 |
桥梁模式 | 将抽象和实现解耦,使得二者能够独立地变化。 桥梁模式的用意是“将抽象化(Abstraction)与实现化(Implementation)脱耦,使得两者能够独立地变化”。 |
桥梁模式在Java应用中的一个很是典型的例子就是JDBC驱动器。JDBC为全部的关系型数据库提供一个通用的界面。一个应用系统动态地选择一个合适的驱动器,而后经过驱动器向数据库引擎发出指令。这个过程就是将抽象角色的行为委派给实现角色的过程。 |
写了一个Android的项目体现23中设计模式,项目如图:算法
测试代码:sql
若是设计模式在编码设计生涯中用得极少,主要缘由是对设计模式的理解还不够,认识不到问题的存在。
项目下载数据库