设计模式

  • 所谓设计模式,就是一套被反复使用的代码设计经验的总结(情境中一个问题经过证实的一个解决方案)。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使人们可以更加简单方便的复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。
  • 在GoF的《Design Patterns: Elements of Reusable Object-Oriented Software》中给出了三类(创建型[对类的实例化过程的抽象化]、结构型[描述如何将类或对象结合在一起形成更大的结构]、行为型[对在不同的对象之间划分责任和算法的抽象化])共23种设计模式,包括:Abstract Factory(抽象工厂模式),Builder(建造者模式),Factory Method(工厂方法模式),Prototype(原始模型模式),Singleton(单例模式);Facade(门面模式),Adapter(适配器模式),Bridge(桥梁模式),Composite(合成模式),Decorator(装饰模式),Flyweight(享元模式),Proxy(代理模式);Command(命令模式),Interpreter(解释器模式),Visitor(访问者模式),Iterator(迭代子模式),Mediator(调停者模式),Memento(备忘录模式),Observer(观察者模式),State(状态模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibility(责任链模式)。

哪些源码用到了设计模式

责任链模式:try-catch、有序广播、viewgroup事件传递
建造者模式:AlertDialog
装饰模式:Collections工具类、I/O、context
观察者模:android中的回调模式、listview的notifyDataChanged、rxjava

外观模式:context
模板方法模式:AsnycTask、Activity
策略:Volley

单例

保证一个类在内存中的对象唯一性。
1,不允许其他程序用new创建该类对象。
2,在该类创建一个本类实例。
3,对外提供一个方法让其他程序可以获取该对象。

好处:

对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销
由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间
饿汉

public class HungurySingleton {private static final HungurySingleton mHungurySingleton = new HungurySingleton();private HungurySingleton(){System.out.println("Singleton is create");}public static HungurySingleton getHungurySingleton() {return mHungurySingleton;}public static void createString(){System.out.println("createString in Singleton");}public static void main(String[] args){HungurySingleton.createString();}
}

  

懒汉
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {// 第一次调用的时候会被初始化if (instance == null) {instance = new LazySingleton();}return instance;}public static void createString(){System.out.println("create String");}public static void main(String[] args){LazySingleton.createString();}
}

  

懒汉安全
public class LazySafetySingleton {private static LazySafetySingleton instance;  private LazySafetySingleton (){}public static void createString(){System.out.println("create String");}public static void main(String[] args){LazySingleton.createString();}//方法中声明synchronized关键字public static synchronized LazySafetySingleton getInstance() {if (instance == null) {  instance = new LazySafetySingleton();  }  return instance;  }//同步代码块实现public static LazySafetySingleton getInstance1() {  synchronized (LazySafetySingleton.class) {  if(instance == null){//懒汉式   instance = new LazySafetySingleton();  }  }  return instance;  }
}

  

DCL

假设没有关键字volatile的情况下,两个线程A、B,都是第一次调用该单例方法,线程A先执行instance = new Instance(),该构造方法是一个非原子操作,编译后生成多条字节码指令,由于JAVA的指令重排序,可能会先执行instance的赋值操作,该操作实际只是在内存中开辟一片存储对象的区域后直接返回内存的引用,之后instance便不为空了,但是实际的初始化操作却还没有执行,如果就在此时线程B进入,就会看到一个不为空的但是不完整(没有完成初始化)的Instance对象,所以需要加入volatile关键字,禁止指令重排序优化,从而安全的实现单例。
加入同步为了解决多线程安全问题。
加入双重判断是为了解决效率问题。 
不写if语句的话,每次都会判断同步锁,这样写的话只在第一次判断并创建对象。以后在不会执行if里的代码了

public class DclSingleton {private static volatile DclSingleton mInstance = null;
//  private static DclSingleton mInstance = null;private DclSingleton() {}public void doSomething() {System.out.println("do sth.");}public static DclSingleton getInstance() {// 避免不必要的同步if (mInstance == null) {// 同步synchronized (DclSingleton.class) {// 在第一次调用时初始化if (mInstance == null) {mInstance = new DclSingleton();}}}return mInstance;}
}

  

静态内部类单例(推荐)
静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。
即当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

public class SingleTon{
  private SingleTon(){}

private static class SingleTonHoler{
  private static SingleTon INSTANCE = new SingleTon();
}

public static SingleTon getInstance(){
  return SingleTonHoler.INSTANCE;
}

  

枚举单例(推荐)
public enum EnumSingleton {//定义一个枚举的元素,它就是 Singleton 的一个实例INSTANCE;  public void doSomeThing() {  // do something...}
}

  

总结

饿汉:无法对instance实例进行延迟加载
懒汉:多线程并发情况下无法保证实例的唯一性
懒汉线程安全:使用synchronized导致性能缺陷
DCL:JVM即使编译器的指令重排序
静态内部类/枚举:延迟加载/线程安全/性能优势

外观模式

外观模式的主要目的在于让外部减少与子系统内部多个模块的交互,从而让外部能够更简单得使用子系统。它负责把客户端的请求转发给子系统内部的各个模块进行处理。
使用场景
1)当你要为一个复杂子系统提供一个简单接口时。
2)客户程序与抽象类的实现部分之间存在着很大的依赖性
3)当你需要构建一个层次结构的子系统时
优点:
1)由于Facade类封装了各个模块交互的过程,如果今后内部模块调用关系发生了变化,只需要修改Facade实现就可以了。
2) Facade实现是可以被多个客户端调用的

public class ModuleA {public void testFuncA() {System.out.println("This is Function From 改变了");}
}
public class ModuleB {public void testFuncB() {System.out.println("This is Function From ModuleB");}
}
public class Facade {private ModuleA moduleA = null;private ModuleB moduleB = null;private ModuleC moduleC = null;private static Facade mFacade = null; private Facade(){moduleA = new ModuleA();moduleB = new ModuleB();moduleC = new ModuleC();}   public static Facade getInstance() {if(mFacade == null) {mFacade = new Facade();}return mFacade;}public void testOperation() {moduleA.testFuncA();moduleB.testFuncB();moduleC.testFuncC();}
}
public class Client {public static void main(String arg[]) {Facade.getInstance().testOperation();}
}

  

装饰模式

  • 对一组对象的功能进行增强时,就可以使用该模式进行问题的解决,是一种对象结构型模式。装饰和继承都能实现一样的特点:进行功能的扩展增强。 但是只为提高功能,进行的继承,会导致继承体系越来越臃肿,不够灵活。
  • 与继承关系相比,关联关系的主要优势在于不会破坏类的封装性,而且继承是一种耦合度较大的静态关系,无法在程序运行时动态扩展。在软件开发阶段,关联关系虽然不会比继承关系减少编码量,但是到了软件维护阶段,由于关联关系使系统耦合性不高,因此使得系统更加容易维护。当然,关联关系的缺点是比继承关系要创建更多的对象。
使用场景

(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
(2)当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式
  • Component: 抽象构件
  • ConcreteComponent: 具体构件
  • Decorator: 抽象装饰类
  • ConcreteDecorator: 具体装饰类
ConcreteDecorator和Decorator都是继承component

public class DecoratorExample {/*** 抽象构件*/interface Component {void operation();}/*** 具体构件*/class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("from ConcreteComponent");}}/*** 抽象装饰类*/class Decorator implements Component {private Component component;  //维持一个对抽象构件对象的引用public Decorator(Component component) { //注入一个抽象构件类型的对象this.component = component;}@Overridepublic void operation() {component.operation();  //调用原有业务方法}}/*** 具体装饰类*/class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}@Overridepublic void operation() {//俩方法位置随便替换super.operation();  //调用原有业务方法addedBehavior();  //调用新增业务方法}//新增业务方法public void addedBehavior() {System.out.println("from ConcreteDecoratorA");}}class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}@Overridepublic void operation() {super.operation();  addedBehavior();  }//新增业务方法public void addedBehavior() {System.out.println("from ConcreteDecoratorB");}}public static void main(String[] args) {//为了方便看就写到一个类里了,理解意思即可
//        ConcreteComponent concreteComponent = new ConcreteComponent();
//        Decorator decorator = new Decorator(concreteComponent);
//        ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(decorator);
//        ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB(concreteDecoratorA);
//        concreteDecoratorB.operation();}
}

  

 

工厂模式

工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。 
工厂类可以根据条件生成不同的子类实例,并且这些对象需要具有共同的接口。
工厂方法模式(Factory Method)分为3种:
1、普通工厂模式
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图:

我们以一个例子来讲解:发送短信和发送邮件(具有共同的接口:发送)

  public interface Sender {  /* * 发送邮件或者短消息的共同接口 */  public void sender();
}  /* * 发送邮件的实现类 */
public class MailSender implements Sender {  public void sender() {  // TODO Auto-generated method stub  System.out.println("this is mailsender!");  }
}
/* * 发送短信的实现类 */
public class SMSSender implements Sender {  public void sender() {  // TODO Auto-generated method stub  System.out.println("this is sms sender!");  }  }
public class SendFactory {  public Sender produce(String type){  if ("mial".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();  }
}

  

静态工厂模式:将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可

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();  }
}

  

工厂模式适用于:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。

抽象工厂模式(Abstract Factory)

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。

这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!

public interface Sender {  public void Send();
}
public class MailSender implements Sender {  @Override  public void Send() {  System.out.println("this is mailsender!");  }
}
public class SmsSender implements Sender {  @Override  public void Send() {  System.out.println("this is sms sender!");  }
}
//工厂类
public class SendMailFactory implements Provider {  @Override  public Sender produce(){  return new MailSender();  }
}  public class SendSmsFactory implements Provider{  @Override  public Sender produce() {  return new SmsSender();  }
}
public interface Provider {  public Sender produce();
}
public class Test {  public static void main(String[] args) {  Provider provider = new SendMailFactory();  Sender sender = provider.produce();  sender.Send();  }
}

  

相关源码:

https://github.com/peiniwan/DesignPattern.git

转载于:https://www.cnblogs.com/sixrain/p/8600319.html

用最简单的例子说明设计模式(一)之单例模式、工厂模式、装饰模式、外观模式...相关推荐

  1. 设计模式GOF23之-------------------结构型模式(适配器模式、代理模式、桥接模式、装饰模式、组合模式、外观模式、享元模式)

    一 结构型模式 二 适配器模式 下面我将用代码模拟键盘usb接口和ps/2的转接器 的适配器过程: 首先定义客户需求: package GOF23;public interface Target {v ...

  2. Java设计模式(四):结构性模式(适配器模式、桥接模式、装饰模式、组合模式、外观模式、亨元模式、代理模式)

    目录 一· 适配器设计模式 1.1 现实生活中的适配器例子 1.2 基本介绍 1.3 工作原理 1.4 类适配器模式 1.5 对象适配器模式 1.6 接口适配器模式 1.7 适配器模式在 Spring ...

  3. 图解Java设计模式学习笔记——结构型模式(适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式、代理模式)

    一.适配器模式(类适配器.对象适配器.接口适配器) 1.现实生活中的例子 泰国插座用的是两孔的(欧标),可以买个多功能转换插头(适配器),这样就可以使用了国内的电器了. 2.基本介绍 适配器模式(Ad ...

  4. JAVA设计模式之(九)门面模式(外观模式)

    本文继续介绍23种设计模式系列之门面模式(外观模式). 医院的例子 现代的软件系统都是比较复杂的,设计师处理复杂系统的一个常见方法便是将其"分而治之",把一个系统划分为几个较小的子 ...

  5. 【设计模式】适配器模式 ( 概念 | 适用场景 | 优缺点 | 外观模式对比 | 适配器模式相关角色 | 类适配器 | 对象适配器 | 实现流程 )

    文章目录 I . 适配器模式概念 II . 适配器模式 适用场景 III . 适配器模式 优缺点 IV . 适配器模式 与 外观模式对比 V . 适配器模式 相关角色 ( 重点 ) VI . 适配器模 ...

  6. 23种设计模式C++源码与UML实现--外观模式

    外观模式 facade模式也叫外观模式,是由GoF提出的23种设计模式中的一种,facade模式为一组具有类似功能的类群,比如类库,子系统等等,提供一个一致的简单界面.这个一致的简单的界面被称为fac ...

  7. C++设计模式 | 四种结构型模式——代理模式、外观模式、适配器模式、装饰模式...

    结构型模式:让类和类进行组合,获得更大的结构. 代理模式 代理模式的定义: 为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端 ...

  8. 【设计模式_青春版】结构型|外观模式

    文章目录 外观模式(结构型) 外观模式又名门面模式 结构 外观模式案例 代码实现 优缺点 优点 缺点 使用场景 在tomcat中的 外观模式(结构型) 外观模式又名门面模式 是一种通过为多个复杂的子系 ...

  9. c语言 适配器模式例子,NodeJS设计模式总结【单例模式,适配器模式,装饰模式,观察者模式】...

    NodeJS设计模式总结[单例模式,适配器模式,装饰模式,观察者模式] 发布时间:2020-08-21 03:08:03 来源:脚本之家 阅读:117 作者:lucky芬 本文实例讲述了NodeJS设 ...

最新文章

  1. linux pcre-devel,ubuntu - 我应该为'pcre-devel'安装什么软件包? - Ubuntu问答
  2. 互联网协议 — 物理介质层
  3. springcloud 文件服务器,SpringCloud传文件
  4. 双指针算法基本原理和实践
  5. 上海女白领吃火锅碰瓷,支付宝口碑居然真的要赔?
  6. 算法题目——省份数量(dfs,bfs)
  7. win10企业版更新和安全中没有 “恢复”这个选项_通知:微软已强制对Windows 10更新升级...
  8. java国家电网面试试题_国家电网笔试面试相关
  9. 为什么Spring需要三级缓存解决循环依赖,而不是二级缓存?
  10. Oracle 存储过程调用语句
  11. java 编程题 实现双色球抽奖游戏中奖号码的生成
  12. 【AWVS】python调AWVS接口 新建扫描并导出扫描报告 [自定义扫描报告](三)
  13. 学习java之java帝国的诞生
  14. R语言中调用windows中的字体方法
  15. 女人为什么要嫁人?(转)
  16. OSError: [WinError 87]参数错误
  17. CSS实现PC端简单的聊天消息气泡样式
  18. 误删暂存代码的恢复方法
  19. 文正机械电子工程专业课_机械电子工程有些什么课程
  20. excel 两组数据交点_如何在百万级的数据里找到别人正在赚钱的项目?【实操长文】...

热门文章

  1. Python 简介day01
  2. IronPython2.7 C# 4.0 互调用备忘
  3. wince 6.0 串口 读取 readfile 超时问题
  4. 【连载】【FPGA黑金开发板】Verilog HDL那些事儿--12864(ST7565P)液晶驱动(十三)...
  5. Testlink在linux上安装遇到的问题
  6. python 时间字符串和时间戳之间的转换
  7. 20162303 结对编程-四则运算(挑战出题)
  8. delphi之http通讯
  9. 解决android Stadio 升级之后 出现乱码
  10. android sqlite 自增长序列号归0