熟练掌握各类设计模式,并能在实际编程开发中灵活运用它们,不只能使代码更规范,重用性更高,同时也能保证代码的可靠性,提升开发效率。这段时间又系统看了设计模式的相关内容,
整理学习总结以下:html
整体来讲设计模式分为三大类:(本文着重讲解标红)
建立型模式,共五种: 工厂方法模式、 抽象工厂模式、 单例模式、 建造者模式、原型模式。
结构型模式,共七种: 适配器模式、装饰器模式、 代理模式、外观模式、桥接模式、组合模式、 享元模式。
行为型模式,共十一种: 策略模式、模板方法模式、 观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
git
面向对象编程有七大原则,即常常提到的Design Pattern,提倡它的根本缘由是为了代码复用,增长可维护性。设计模式就是实现了这些原则,从而达到了代码复用、增长可维护性的目的。算法
由于设计模式就是基于这些原则的实现,因此颇有必要了解这些原则,下面主要对面向对象编程的几个原则进行简单介绍。编程
英文全称是Single Responsibility Principle,定义是一个类,应该只有一个引发它变化的缘由。类变化的缘由就是职责,若是一个类承担的职责过多,就等于把这些职责耦合在一块儿了。一个职责的变化可能会削弱或者抑制这个类完成其余职责的能力。这种耦合会致使脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。而若是想要避免这种现象的发生,就要尽量的遵照单一职责原则。此原则的核心就是解耦和加强内聚性。设计模式
英文全称是Open Close Principle,定义是软件实体(包括类、模块、函数等)应该对于扩展时开放的,对于修改是封闭的。开闭原则是是面向对象设计中最重要的原则之一,其它不少的设计原则都是实现开闭原则的一种手段。数组
英文全称是Liskov Substitution Principle,是面向对象设计的基本原则之一。 定义是任何基类能够出现的地方,子类必定能够出现。LSP 是继承复用的基石,只有当派生类能够替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也可以在基类的基础上增长新的行为。里氏替换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,因此里氏替换原则是对实现抽象化的具体步骤的规范。安全
英文全称是Dependence Inversion Principle,这个原则是开闭原则的基础,依赖倒置原则就是要求调用者和被调用者都依赖抽象,这样二者没有直接的关联和接触,在变更的时候,一方的变更不会影响另外一方的变更。依赖倒置强调了抽象的重要性,针对接口编程,依赖于抽象而不依赖于具体。数据结构
英文全称是Interface Segregation Principle,这个原则的意思是使用多个隔离的接口,比使用单个接口要好。目的就是下降类之间的耦合度,便于软件升级和维护。闭包
一个实体应当尽可能少地与其余实体之间发生相互做用,使得系统功能模块相对独立。通俗地说就是不要和陌生人说话,即一个对象应对其余对象有尽量少的了解。迪米特法则的初衷在于下降类之间的耦合。因为每一个类尽可能减小对其余类的依赖,所以,很容易使得系统的功能模块功能独立,相互之间不存在(或不多有)依赖关系。并发
英文全称是Composite Reuse Principle,合成/聚合复用原则常常又叫作合成复用原则。合成/聚合复用原则的潜台词是:我只是用你的方法,咱们不必定是同类。继承的耦合性更大,好比一个父类后来添加实现一个接口或者去掉一个接口,那子类可能会遭到毁灭性的编译错误,但若是只是组合聚合,只是引用类的方法,就不会有这种巨大的风险,同时也实现了复用。
建立型模式是指这些设计模式提供了一种在建立对象的同时隐藏建立逻辑的方式,而不是使用新的运算符直接实例化对象。这使得程序在判断针对某个给定实例须要建立哪些对象时更加灵活
确保某一个类只有一个实例,并自行实例化向整个系统提供这个实例。
单例模式理解起来不难,典型例子有一个公司只能有一个CEO。它主要是为了保证一个类仅有一个实例,这个类中本身提供一个返回实例的方法,方法中先判断系统是否已经有这个单例,若是有则返回,若是没有则建立。若是建立多个实例会消耗过多的资源或者某种类型的对象只应该有且只有一个时,应该考虑使用单例模式。
单例模式理解起来不难,重要的是须要掌握它的几种常见写法。
public class Singleton { // 直接建立对象 public static Singleton instance = new Singleton(); // 私有化构造函数 private Singleton() { } // 返回对象实例 public static Singleton getInstance() { return instance; } }
懒汉式:
//写法1、懒汉式写法 public class Singleton { private static Singleton instance; //构造函数私有 private Singleton (){ } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
//写法1、懒汉式写法 public class Singleton { private static Singleton instance; //构造函数私有 private Singleton (){ } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
//写法2、DCL(Double Check Lock) 双重校验锁 public class Singleton { private volatile static Singleton singleton; private Singleton (){ } public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
//写法3、静态内部类单例模式 public class Singleton { private Singleton (){ } public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } }
定义一个用于建立对象的接口,让子类决定实例化哪个类。
工厂方法模式分为三种:普通工厂模式,就是创建一个工厂类,对实现了同一接口的一些类进行实例的建立。多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,若是传递的字符串出错,则不能正确建立对象,而多个工厂方法模式是提供多个工厂方法,分别建立对象。静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不须要建立实例,直接调用便可 .
(1)普通工厂模式
public interface Sender { public void Send(); } public class MailSender implements Sender { @Override public void Send() { System.out.println("this is mail sender!"); } } public class SmsSender implements Sender { @Override public void Send() { System.out.println("this is sms sender!"); } } public class SendFactory { public Sender produce(String type) { if ("mail".equals(type)) { return new MailSender(); } else if ("sms".equals(type)) { return new SmsSender(); } else { System.out.println("请输入正确的类型!"); return null; } } }
(2)多个工厂模式
该模式是对普通工厂方法模式的改进,在普通工厂方法模式中,若是传递的字符串出错,则不能正确建立对象,而多个工厂方法模式是提供多个工厂方法,分别建立对象。
public interface Sender { public void Send(); } public class MailSender implements Sender { @Override public void Send() { System.out.println("this is mail sender!"); } } public class SmsSender implements Sender { @Override public void Send() { System.out.println("this is sms sender!"); } } public class SendFactory { public Sender produce(String type) { if ("mail".equals(type)) { return new MailSender(); } else if ("sms".equals(type)) { return new SmsSender(); } else { System.out.println("请输入正确的类型!"); return null;
public class SendFactory { public Sender produceMail(){ return new MailSender(); } public Sender produceSms(){ return new SmsSender(); } } public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produceMail(); sender.send(); } }
(3)静态工厂模式
静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不须要建立实例,直接调用便可
public class SendFactory { public static Sender produceMail(){ return new MailSender(); } public static Sender produceSms(){ return new SmsSender(); } } public class FactoryTest { public static void main(String[] args) { Sender sender = SendFactory.produceMail(); sender.send(); } }
工厂方法模式有一个问题就是,类的建立依赖工厂类,也就是说,若是想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,因此,从设计角度考虑,有必定的问题,如何解决?就用到抽象工厂模式,建立多个工厂类,这样一旦须要增长新的功能, 直接增长新的工厂类就能够了,不须要修改以前的代码。
代码仍是在工厂方法模式的基础上改进
public interface Provider { public Sender produce(); } ---------------------------------------------------------------------------- public interface Sender { public void send(); } ---------------------------------------------------------------------------- public class MailSender implements Sender { @Override public void send() { System.out.println("this is mail sender!"); } } --------------------------------------------------------------------------- public class SmsSender implements Sender { @Override public void send() { System.out.println("this is sms sender!"); } } --------------------------------------------------------- public class SendSmsFactory implements Provider { @Override public Sender produce() { return new SmsSender(); } } public class SendMailFactory implements Provider { @Override public Sender produce() { return new MailSender(); } } ------------------------------------------------------------- public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.send(); } }
工厂类模式提供的是建立单个类的模式,而建造者模式则是将各类产品集中起来进行管理,用来建立复合对象,所谓复合对象就是指某个类具备不一样的属性,其实建造者模式就是前面抽象工厂模式和最后的 Test 结合起来获得的
public class Builder { private List<Sender> list = new ArrayList<Sender>(); public void produceMailSender(int count) { for (int i = 0; i < count; i++) { list.add(new MailSender()); } } public void produceSmsSender(int count) { for (int i = 0; i < count; i++) { list.add(new SmsSender()); } } }
public class TestBuilder { public static void main(String[] args) { Builder builder = new Builder(); builder.produceMailSender(10); } }
用原型实例指定建立对象的种类,而且经过拷贝这些原型建立新的对象。
原型模式不难理解,它主要是用在实例建立的时候,由于有的时候咱们经过new建立一个对象时可能成本太高,这时咱们能够考虑直接经过直接克隆实例快速建立对象。克隆后的实例与原实例内部属性一致。原型模式须要注意一个深拷贝和浅拷贝的问题。
适配器模式将某个类的接口转换成客户端指望的另外一个接口表示,目的是消除因为接口不匹配所形成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式
public class Source { public void method1() { System.out.println("this is original method!"); } } ------------------------------------------------------------- public interface Targetable { /* 与原类中的方法相同 */ public void method1(); /* 新类的方法 */ public void method2(); } public class Adapter extends Source implements Targetable { @Override public void method2() { System.out.println("this is the targetable method!"); } } public class AdapterTest { public static void main(String[] args) { Targetable target = new Adapter(); target.method1(); target.method2(); } }
基本思路和类的适配器模式相同,只是将 Adapter 类做修改,此次不继承 Source 类,而是持有 Source 类的实例,以达到解决兼容性的问题
public class Wrapper implements Targetable { private Source source; public Wrapper(Source source) { super(); this.source = source; } @Override public void method2() { System.out.println("this is the targetable method!"); } @Override public void method1() { source.method1(); } } -------------------------------------------------------------- public class AdapterTest { public static void main(String[] args) { Source source = new Source(); Targetable target = new Wrapper(source); target.method1(); target.method2(); } }
接口的适配器是这样的:有时咱们写的一个接口中有多个抽象方法,当咱们写该接口的实现类时,必须实现该接口的全部方法,这明显有时比较浪费,由于并非全部的方法都是咱们须要的,有时只须要某一些,此处为了解决这个问题,咱们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了全部的方法,而咱们不和原始的接口打交道,只和该抽象类取得联系,因此咱们写一个类,继承该抽象类,重写咱们须要的方法就行。
将抽象部分与实现部分分离,使它们均可以独立的变化。
在软件系统中,某些类型因为自身的逻辑,它具备两个或多个维度的变化,那么如何应对这种“多维度的变化”?这就要使用桥接模式。桥接模式须要重点理解的抽象部分,实现部分,脱耦。一个典型的例子是咖啡加糖问题,抽象部分有Coffee,其下有LargeCoffee,SmallCoffee,实现部分是CoffeeAdd,其下有Sugar,Normal,抽象类Coffee中引用CoffeeAdd,这样CoffeeAdd其实就是一个桥接。查看更多
public interface Sourceable { public void method(); } ---------------------------------------------------- public class Source implements Sourceable { @Override public void method() { System.out.println("the original method!"); } } ---------------------------------------------------- public class Decorator implements Sourceable { private Sourceable source; public Decorator(Sourceable source) { super(); this.source = source; } @Override public void method() { System.out.println("before decorator!"); source.method(); System.out.println("after decorator!"); } } ---------------------------------------------------- public class DecoratorTest { public static void main(String[] args) { Sourceable source = new Source(); Sourceable obj = new Decorator(source); obj.method(); } }
将对象组合成树形结构以表示“部分-总体”的层次结构,使得用户对单个对象和组合对象的使用具备一致性。
组合模式理解起来相对简单,典型的例子就是假设公司A,里面有不一样的部门,不一样的部分下有不一样的员工,这样一个部门下的全部员工组合成了一个部门,全部部门组合成了整个公司。
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式的一个典型例子是去医院看病,挂号、门诊、划价、取药,让患者或患者家眷以为很复杂,若是有提供接待人员,只让接待人员来处理,就很方便。点击查看更多
运用共享技术有效地支持大量细粒度的对象。
在有大量对象时,有可能会形成内存溢出,咱们把其中共同的部分抽象出来,若是有相同的业务请求,直接返回在内存中已有的对象,避免从新建立。点击查看更多
为其余对象提供一种代理以控制对这个对象的访问。
代理模式主要解决在直接访问对象时带来的问题。举个例子,猪八戒去找高翠兰结果是孙悟空变的,能够这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,因此说孙悟空是高翠兰代理类。点击查看更多
这些设计模式特别关注对象之间的通讯。
一个操做中的算法的框架,而将一些步骤延迟到子类中,使得子类能够不改变一个算法的结构便可重定义该算法的某些特定步骤。
模板方法模式一个典型例子就是Android中的异步任务类AsyncTask,它对异步任务的执行进行了流程封装,子类继承它时,只需在指定的流程中实现具体的操做便可。点击查看更多关于模板方法模式的介绍
将一个请求封装为一个对象,从而可用不一样的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操做
命令模式主要是经过调用者调用接受者执行命令,这个模式中须要理解的是三个角色:(1) Receiver 真正的命令执行对象 (2) Command 持有一个对Receiver的引用,调用Receiver的相关方法。(3) Invoker 请求者,持有一个对Command的引用,调用Command的方法执行具体命令。点击查看更多关于命令模式的介绍
提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
在Java集合框架中咱们知道对于一个指定的集合类,咱们可使用一个特定的Iterator迭代器来对集合中的全部元素进行遍历。这样结合来看,迭代器模式很好理解了。点击查看更多
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被自动更新。
观察者模式能够结合Android中的ListView来理解,ListView关联的适配器Adapter在数据发生变化时会经过notifyDataSetChanged()方法来通知界面刷新。点击查看更多介绍
用一个中介对象来封装一系列的对象交互。中介者使各对象不须要显式地相互引用,从而使其耦合松散,并且能够独立地改变它们之间的交互。
中介者模式的典型例子就是未加入 WTO 以前各个国家相互贸易,结构复杂,你们都加入WTO后是各个国家经过 WTO 来互相贸易,变得规范。点击查看更多介绍
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象以外保存这个状态。这样之后就可将该对象恢复到保存的状态。
备忘录模式的典型例子就是git版本管理工具,它帮咱们保存了每次提交后的项目状态,在必要的时候咱们能够回退到指定的版本中。点击查看更多
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器的典型例子是在编译原理中的应用,若是一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就能够构建一个解释器,该解释器经过解释这些句子来解决该问题。点击查看更多
容许一个对象在其内部状态改变时改变它的行为。对象看起来彷佛修改了它的类。
状态模式主要解决对象的行为依赖于它的状态(属性),而且能够根据它的状态改变而改变它的相关行为。典型的例子是一我的在不一样的状态下完成一件事的结果多是不一样的。点击查看更多
定义一系列的算法,把它们一个个封装起来, 而且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
从策略模式的定义能够看到它主要是将算法和客户独立开,一个典型的例子是排序算法,咱们给定一个数组,输出排序后的结果,可是过程当中咱们能够采起不一样的排序算法,这些算法其实就是策略。点击查看更多
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
责任链模式,避免请求发送者与接收者耦合在一块儿,让多个对象都有可能接收请求,将这些对象链接成一条链,而且沿着这条链传递请求,直到有对象处理它为止。点击查看更多
封装一些做用于某种数据结构中的各元素的操做。它使你能够在不改变各元素的类的前提下定义做用于这些元素的新操做。
访问者模式是一种将数据操做和数据结构分离的设计模式,它一般使用在对象结构比较稳定,可是常常须要在此对象结构上定义新的操做,或者须要对一个对象结构中的对象进行不少不一样的而且不相关的操做,而须要避免让这些操做"污染"这些对象的类,使用访问者模式将这些封装到类中。点击查看更多
到这里,Java设计模式的学习总结就结束了,由于我的能力有限,有些模式只是简单介绍了一下,想要进一步学习的话仍是要靠你们本身去查阅相关资料学习。熟练地掌握设计模式,还需多多的实践.