《设计模式》笔记(未完)

《设计模式》笔记(未完)

2018, May 10    

策略模式

观察者模式

装饰者模式

工厂模式

简单工厂

简单工厂模式是用一个工厂来创建对象。简单工厂抽象了产品对象(也可以不抽象)。工厂是一个直接引用的类,用来直接根据指定的参数来创建不同类型的对象。(一般用到的也就只是简单工厂了)

工厂模式

工厂模式是通过不同类型的工厂创建不同的对象。工厂模式抽象了产品对象和工厂,对外使用抽象的工厂,而不同产品的区分是由特定的工厂来决定的。特定的工厂可以按照简单工厂去实现。工厂生产出来的直接是面向对象的成品,只能创建一个具体产品类的实例。

抽象工厂模式

抽象工厂是为创建不同的产品族。抽象工厂抽象的产品族,(抽象中已经定义好了要生产哪些产品),工厂生产出来的是面向对象产品的组成部分,所以工厂产品生成也是可以抽象的。 具体工厂类可以创建多个产品,这些产品有一定的依赖关系。增加某一个产品的不同类型容易,但是难以增加新的类型的产品。比如可以增加原料的不同类型,但是增加新的原料不容易。

单件模式

简单单例

private static Singleton instance;
private Singleton() { }
public static Singleton getInstance() {
	if (instance == null)
		instance == new Singleton();
	return instance;
}

问题:多线程中调用,在初始化同时判定为null时,可能会出现创建多个不同实例。
场景:简单高效,不考虑多线程问题时可使用。延迟创建。

提前创建

private static Singleton instance = new Singleton();
pricate Singleton() {}
public static Singleton getInstance() {
	return instance;
}

问题:开始时创建会一直保存这个实例,即使用不到
场景:?

双重检查加锁

public static synchronized getInstance() {
	if (instance == null)
		instance == new Singleton();
	return instance;
}
private violate static Singleton instance;
public static Singleton getInstance() {
	synchronized (Singleton.class) {    
		if (singleton == null)
			instance = new Singleton();    
    }
	return instance;
}

以上两种情况相同,这种加锁方式会导致每次在调用getInstance方法时都会有加锁释放锁的消耗,书上说锁操作会降级100倍的效率,并且其实只有在instance为空时需要判断是否加锁,所以这种锁比较多余。

private violate static Singleton instance;
public static Singleton getInstance() {
	if (singleton == null) {
		synchronized (Singleton.class) { 
			if (singleton == null)  
				instance = new Singleton();    
		}
    }
	return instance;
}

这个方法中增加了violate关键字保证instance的内存可见性,因为synchronized是对Singleton类进行加锁的,并没有在instance实现同步,如果有两个线程同时到synchronized代码块时,只有一个进入并初始化了instance,保证了访问上的独占性,不能保证instance的内存可见性,结果会导致第二个线程不能马上看见instance被初始化,有可能会再次实例化instance。因此增加了violate关键字,保证变量的内存可见性,并且同步的消耗也非常小。

private Singleton(){}
    
private static class SingleHolder{
    public static Singleton instance = new Singleton();
}
    
public static Singleton getInstance(){
     return SingleHolder.instance;
}

这种方式通过全局静态变量的提前创建解决了同步问题,通过getInstance实现了延迟加载


violate关键字
特性一:内存可见性,即线程A对volatile变量的修改,其他线程获取的volatile变量都是最新的。读操作时JMM会把工作内存中对应的值设为无效,要求线程从主内存中读取数据;写操作时JMM会把工作内存中对应的数据刷新到主内存中,这种情况下,其它线程就可以读取变量的最新值。
volatile特性二:可以禁止指令重排序
https://blog.csdn.net/u011519624/article/details/63686701
https://www.jianshu.com/p/195ae7c77afe

内存可见性

如果线程A对共享变量X进行了修改,但是没有及时把更新后的值刷入到主内存中,而此时线程B从主内存读取共享变量X的值,所以X的值是原始值,那么我们就说对于线程B来讲,共享变量X的更改对线程B是不可见的。


注意

  1. 类加载器可能会造成出现多个单例实例的情况,可能需要考虑重写类加载器
  2. 1.4?java版本之前单例会由于只被本类引用而被回收,出现下载调用不是一个实例的情况
  3. 实现注册表?
  4. 单例不应该被滥用,需要的场景其实很少,所以项目中出现多个单例时,需要检查是否有设计问题

    命令模式

    适配器模式

    对象适配模式

    类适配模式

    外观模式

    模板方法

    迭代器与组合模式

    状态模式

    代理模式

    复合模式