设计模式简介(转)

一 设计模式简介

  设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 

二 设计模式分类

总体来说设计模式分为三类

创建型模式,共五种:工厂方法模式抽象工厂模式单例模式、建造者模式、原型模式。

意义:创建对象时,不再直接实例化对象,而是根据特定场景,有程序确定创建对象的方式,从而保证更大的性能、更好的性能优势。

 

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

意义:用于帮助将多个对象组织成更大的结构。

 

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

其实还有两类:并发型模式和线程池模式。

意义:用于帮助系统间各对象的通信,如何控制复杂系统的流程。

 三 设计模式的六大原则

1 单一职责原则:不要存在多于一个导致类变更的原因,即一个类只需实现一项职责,主要可以实现高内聚、低耦合。

2 开放封闭原则:对于扩展是开放的,对于修改是关闭的。(目的)

3 里氏替换原则:任何基类可以出现的地方,子类一定可以出现。(实现)

4 依赖倒置原则:高层次的模块、低层次的模块与具体实现都应该依赖于抽象,也可以说应该依赖于接口编程。(方法)

5 接口隔离原则:接口应该只处理一类定制的方法。

6 迪米特法则:又叫最少知道原则,就是说一个对象应当对其他对象有尽可能少的了解,也可以说一个类应该对自己需要耦合或调用的类知道得最少。

四 单例模式介绍

1 单例模式概念:单例模式确保某一个类有且仅有有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

2 常见实现方法:

  1. 懒汉式,线程不安全
  2. 懒汉式,线程安全
  3. 饿汉式
  4. 饿汉式,变种
  5. 静态内部类
  6. 双重检验锁
  7. 登记式
1)懒汉式,线程不安全,代码如下:

public classSingleton {

  private static Singleton instance;

  private Singleton() {

  }

  public static Singleton getInstance(){

    if (instance == null) {

    instance = new Singleton();

  }

  return instance;

}

}

上述代码很简单,但是是线程不安全的,多线程情况下不能正常工作,会创建多个实例。
 
 
2)懒汉式,线程安全,代码如下:
public classSingleton {

  private static Singleton instance;

  private Singleton(){

  }

  public static synchronized Singleton getInstance() {//同步锁

    if (instance== null) {#1

    instance = new Singleton();#2

  }

  return instance;#3

  }

}

 

当系统有两个线程线程1和线程2,两线程到达#1前,若线程1(或线程2)抢到锁,执行#2,#3后释放锁,若线程2(或线程1)抢到锁,会执行#2,由于instance为静态类变量,此时的instance已由线程1实例化了,因此线程2没有执行#2,因此系统只有一个实例化对象。所以该代码是线程安全的。缺点:尽管该代码是线程安全的,能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是效率低,99%情况下不需要加锁、解锁的同步操作。

 
3)饿汉式,代码如下:
public class Singleton {

   private static Singleton instance = new Singleton();

   private Singleton (){

   }

    public static Singleton getInstance() {

     return instance;

   }

}

上述代码在类一加载便实例化instance,因此称为饿汉式

 

 

4)饿汉式,变种,代码如下:
public class Singleton { 

  private Singleton instance = null; 

  static {

    instance = new Singleton(); 

  }

  private Singleton (){} 

  public static Singleton getInstance() { 

    return this.instance; 

} 

}
上述代码是3)的变种,其实是一样的。
 
 
5)静态内部类,代码如下:
public class Singleton {

  private static class SingletonHolder {

  private static final Singleton INSTANCE = newSingleton();

  }

  private Singleton (){}

  public static final Singleton getInstance(){

    return SingletonHolder.INSTANCE;

 }

}

相对于第三种方式,这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显式通过调用getInstance方法时,才会显式装载SingletonHolder类,从而实例化instance。例如,如果实例化instance很消耗资源,我想让其延迟加载,另一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。

 

6)双重校验锁:“双重检查加锁”的方式可以既实现线程安全,又能够使性能不受到很大的影响。

所谓双重检查加锁机制指的是:并不是每次进getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。

重检查加锁机制的实现会使用一个关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。(对于volatile修饰的变量,系统内的线程所有的write都将先行发生于read)

说明:由于volatile关键字可能会屏蔽掉虚拟机中的一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用“双重检查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用。

public class Singleton {

  private volatile static Singleton singleton;

  private Singleton (){}

  public static Singleton  getInstance() { 

    if (singleton == null) {#2

    synchronized (Singleton.class) {

      if (singleton == null) { 

      singleton = new Singleton(); 

      } 

    } 

    }  
  return singleton; 

  } 

} 

注:很显然上述代码是线程安全的,然而细心的朋友可以发现,如果把去掉第一重判断#2,此时的代码也是线程安全的,与单例第二种实现方式没有本质的区别,那么为什么加上#2呢,好处有:提高代码运行效率,当线程1实例了singleton后,此时线程2判断singleton不为空,那么synchronized同步代码并需要执行,因为加锁、解锁很大的影响系统性能,尽量少用。

 

 

7)登记式,可继承:
细心的朋友可以看出懒汉式或者恶汉式的单例模式并不能被继承,并没有体现面向对象的优势,看到网上有博友实现的登记式代码很长很繁琐,因此贴出相对简洁的可继承的登记式单例模式的代码是很有必要的,我也是才学习到,是腾讯大神分享给我的。
下面代码是Google公司自己写的代码,不愧是牛逼公司,代码简洁,代码如下:
public abstract class Singleton<T> {

private T mInstance;

    protected abstract T create();

    public final T get() {

        synchronized (this) {

            if (mInstance == null) {

                mInstance = create();

            }

            return mInstance;

        }

    }

}

 

 
由于静态类是需要继承才能实现起内部方法,是不是so easy!
如何继承呢?
 
public class AManager {

  private static final Singleton<AManager> sInstance = new Singleton<AManager>()

  @Override

  protected AManager create() {

    return new AManager();

  }

};

  public static AManager getInstance(){

    return sInstance.get();

  }
  
private AManager(){     System.out.println("AManager created!");   } }

 

 

 

参考:http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html

     http://blog.csdn.net/u014539776/article/details/50775470

posted @ 2017-03-13 10:01  专注如一  阅读(291)  评论(0编辑  收藏  举报