
《设计模式》笔记(未完)
策略模式
观察者模式
装饰者模式
工厂模式
简单工厂
简单工厂模式是用一个工厂来创建对象。简单工厂抽象了产品对象(也可以不抽象)。工厂是一个直接引用的类,用来直接根据指定的参数来创建不同类型的对象。(一般用到的也就只是简单工厂了)
工厂模式
工厂模式是通过不同类型的工厂创建不同的对象。工厂模式抽象了产品对象和工厂,对外使用抽象的工厂,而不同产品的区分是由特定的工厂来决定的。特定的工厂可以按照简单工厂去实现。工厂生产出来的直接是面向对象的成品,只能创建一个具体产品类的实例。
抽象工厂模式
抽象工厂是为创建不同的产品族。抽象工厂抽象的产品族,(抽象中已经定义好了要生产哪些产品),工厂生产出来的是面向对象产品的组成部分,所以工厂产品生成也是可以抽象的。 具体工厂类可以创建多个产品,这些产品有一定的依赖关系。增加某一个产品的不同类型容易,但是难以增加新的类型的产品。比如可以增加原料的不同类型,但是增加新的原料不容易。
单件模式
简单单例
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.4?java版本之前单例会由于只被本类引用而被回收,出现下载调用不是一个实例的情况
- 实现注册表?
- 单例不应该被滥用,需要的场景其实很少,所以项目中出现多个单例时,需要检查是否有设计问题
命令模式
适配器模式
对象适配模式
类适配模式
外观模式
模板方法
迭代器与组合模式
状态模式
代理模式
复合模式