设计模式总结一

模板方法
模板方法模式定义:
        义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可中定义该算法的没写特定步骤。
这个应用在设计框架级功能的时候非常的有用,框架定义好了算法的步骤,在跟据不同的需求实现具体的算法,比如在DAO显示中设计通用的增删改查功能。同时,模板方法还提供了一个额外的好处,就是可以控制子类的扩展,因为在父类定义好了算法的步骤,只是几个固定的点才会调用被子类实现的方法,因此也就在这几个点来扩展功能,这些可以被子类覆盖以扩展功能的方法通常被成为“钩子”方法。
把模板实现成为抽象类,为所有的子类提供了公共的功能,就是定义了具体的算法骨架;同时在模板中把需要由子类扩展的具体步骤的算法定义为抽象方法,要求子类去实现这些方法,这就约束了子类的行为。
延伸:抽象类经常被使用的一个情况,既要约束子类的行为,又为子类提供公共的功能。

         策略模式的功能是把具体的算法实现,从具体的业务处理里面独立出来,把它们实现成为单独的算法类,从而形成一系列的算法,并让这些算法可以相互替换。
策略模式的重心不是如何来实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活、具有更好的维护性和扩展性。

策略模式调用顺序
策略模式的调用顺序,有两种常见的情况,一种如下:
  先是客户端来选择并创建具体的策略对象
  然后客户端创建上下文
  接下来客户端就可以调用上下文的方法来执行功能了,在调用的时候,从客户端传入算法需要的参数
  上下文接到客户的调用请求,会把这个请求转发给它持有的Strategy

 策略模式适用的场景比如不同的客户不同的报价(客户年限,累计消费金额,一次购买金额,销售人员的浮动),不同时期不同的价格(公司活动,过程促销时间,价格回调)

单例模式

双重检查加锁机制

        单例模式是我们最熟悉,最常用的模式,下面介绍“双重检查加锁”的实现,可以既实现线程安全,又能够使性能不受到大的影响。那么什么是“双重检查加锁”机制呢?
所谓双重检查加锁机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检
查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
双重检查加锁机制的实现会使用一个关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
注意:在Java1.4及以前版本中,很多JVM对于volatile关键字的实现有问题,会导致双重检查加锁的失败,因此双重检查加锁的机制只能用在Java5及以上的版本。
看看代码可能会更清楚些,示例代码如下:
public class Singleton {
 /**
  * 对保存实例的变量添加volatile的修饰
  */
 private volatile static Singleton instance = null;

 private Singleton() {
 }

 public static Singleton getInstance() {
  // 先检查实例是否存在,如果不存在才进入下面的同步块
  if (instance == null) {
   // 同步块,线程安全的创建实例
   synchronized (Singleton.class) {
    // 再次检查实例是否存在,如果不存在才真的创建实例
    if (instance == null) {
     instance = new Singleton();
    }
   }
  }
  return instance;
 }
}

单例模式的懒汉式实现方式体现了延迟加载的思想,什么是延迟加载呢?
通俗点说,就是一开始不要加载资源或者数据,一直等,等到马上就要使用这个资源或者数据了,躲不过去了才加载,所以也称Lazy Load,不是懒惰啊,是“延迟加载”,这在实际开发中是一种很常见的思想,尽可
能的节约资源。需要先得到类实例,然后才可以调用,可是这个方法就是为了得到类实例,这样一来不就形成一个死循环了吗? public static Singleton getInstance() {}

更好的方案
         要想很简单的实现线程安全,可以采用静态初始化器的方式,它可以由JVM来保证线程安全性。比如前面的“饿汉式”实现方式,但是这样一来,不是会浪费一定的空间吗?因为这种实现方式,会在类装载的时候就
初始化对象,不管你需不需要。
如果现在有一种方法能够让类装载的时候不去初始化对象,那不就解决问题了?一种可行的方式就是采用类级内部类,在这个类级内部类里面去创建对象实例,这样一来,只要不使用到这个类级内部类,那就不会创建对象实例。从而同时实现延迟加载和线程安全。
看看代码示例可能会更清晰,示例代码如下:
public class SingletonT {
 /**
  * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
  * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
  */
 private static class SingletonHolder {
  /**
   * 静态初始化器,由JVM来保证线程安全
   */
  private static SingletonT instance = new SingletonT();
 }

 /**
  * 私有化构造方法
  */
 private SingletonT() {
 }

 public static SingletonT getInstance() {
  return SingletonHolder.instance;
 }
}
当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会被虚拟机在装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。
        这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值