设计模式简述

设计模式分类

  • 创建性模型:对对象创建过程的各种问题和解决方法的总结
工厂模式(Factory,Abstract Factory)
单例模式(singleton)
构建器模式(Buider)
原型模式(Pototype)
  • 结构型模式:是对软件设计结构的总结,关注与类、对象继承、组合方式的实践经验
桥接模式(Bridge)
适配器模式(Adapter)
装饰器模式(Decorator)
代理模式(Proxy)
组合模式(Composite)
外观模式(Facade)
享元模式(Flyweight)
  • 行为型模式:从类与对象交互、职责划分等角度总结的模式
策略模式(strategy)
解释器模式(Interpeter)
命令模式(Command)
观察者模式(Observer)
迭代器模式(Iterator)
模板方法模式(Template Method)
访问者模式(Visitor)

创建应用场景

识别装饰器

1.案例
InputSteam是一个抽象类,标准库提供FileInputStream,ByteArrayInputStream等各种不同子类,分别从不同角度对InputStream进行扩展
2.识别依据
通过**识别类设计特征**判断,即类构造函数以**相同**的**抽象类或接口**作输入参数,本质保证同类型实例,对目标对象调用,会通过保证覆盖过的方法,以后调用被包装实例,
自然会实现增加额外逻辑的目的,即所谓“装饰”,实例如下:BufferInputStream经过包装,为输入流过程增加缓存,类似包装器还可多次嵌套,不断增加不同层次功能。
public BufferedInputStream(InputStream in)
  • InputStream装饰器实践
    InputStream装饰器实践

构建器模式

1.案例
最新jdk版本中 HTTP/2 Client API ,下面这个场景HttpRequest工厂,即典型构建起模式,通常被实现成fluent风格的API,也叫方法链

HttpRequest request = HttpRequest.newBuilder(new URI(uri))
                     .header(headerAlice, valueAlice)
                     .headers(headerBob, value1Bob,
                      headerCarl, valueCarl,
                      headerBob, value2Bob)
                     .GET()
                     .build();

2.优点:优雅解决否则复杂对象、传入复杂参数的麻烦,"复杂"是指类似要输入参数组合多,如果用构造函数,往往要为每一种可能参数组合实现相应构造函数
一系列的复杂构造函数会让代码可读性和维护性变得很差。
3.小结:上一步反映创建型模式初衷,即对象创建过程单独抽象出来,从结构把对象使用逻辑和创建逻辑相互独立,隐藏对象实例的细节,进而为使用者实现更加规范、统一的逻辑。

单例模式

  • 简单例子
1.饱死鬼模式:无论应用是否请求单例对象,都要创建。
缺点:但是不能保证额外的对象不被创建处理,别人完全使用默认空参构造器可以直接"new Singleton()"
public class Singleton {
       private static Singleton instance = new Singleton();
       public static Singleton getInstance() {
          return instance;
       }
    }
  • 改进后单例模式
结合ConcurrentHashMap用到的lazy-load机制,可以在对象需要进行实例化,再被应用线程请求获取,改善初始内存开销,单例同样适用。
缺点:单线程不存在问题,在并发时需要考虑线程安全。可以用double check。
public class Singleton {
        private static Singleton instance;
        private Singleton() {
        }
        public static Singleton getInstance() {
            if (instance == null) {
            instance = new Singleton();
            }
        return instance;
        }
    }
  • 最终单例模式
使用volatile 类型修饰单例对象提供线程间可见性,并初始化为null(改善初始内存开销),已经保证getInstance返回的是**初始完全**的对象
在同步之前进行null检查,以尽量避免开销较大的同步块
直接在class基本进行同步,保证线程安全的类方法(类方法即静态方法)调用。

public class Singleton {
  private static volatile Singleton singleton = null;
  private Singleton() {
  }

  public static Singleton getSingleton() {
      if (singleton == null) { // 尽量避免重复进入同步块
          synchronized (Singleton.class) { // 同步.class,意味着对同步类方法调用
              if (singleton == null) {
                  singleton = new Singleton();
              }
          }
      }
      return singleton;
  }
}

争论:争议较大的是volatile修饰类的私有静态变量,当Single通本身有多个成员变量是,需要保证初始化完成后,才能被get到。
现代Java中,内存排序模型(JMM)已经非常完成,通过volatile的write或read,能够保证happen-before,避免volatile变量前面的类成员变量被排序到后面,造成数据修改问题,即避免编译器的指令重拍。
换句话说,构造的对象store指令能够被保证一定在volatile read之前。
当然,也有推荐使用内部类持有静态对象的方式实现,理论是依据对象初始化过程的初始化锁。这种和前面double-check锁都能保证线程安全,但语法稍显羞涩,不具特别优势。如下:

public class Singleton {
  private Singleton(){}
  public static Singleton getSingleton(){
      return Holder.singleton;
  }

  private static class Holder {
      private static Singleton singleton = new Singleton();
  }
}

- java核心库单例

java.lang.Runtime并未实现double-check锁,而是静态实例别声明为final,被通常实践忽略,一定程度保证实例不被串改(反射之类可以绕过是私有访问限制)
也有限保证执行顺序语义,代码如下:

private static final Runtime currentRuntime = new Runtime();
private static Version version;
// …
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don’t let anyone else instantiate this class */
private Runtime() {}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值