Java 23 种设计模式之单例模式
设计模式:是一套被重复应用,少数人通晓的,通过分类编目标,代码设计教训的总结。
一:设计模式的分类
创立型模式,共五种:工厂办法模式, 形象工厂模式,单例模式 , 建造者模式, 原型模式
结构型模式,共七种:适配器模式,装璜器模式,代理模式,外观模式,桥接模式,组合模式,享元模式
行为型模式,共十一种:策略模式,模板办法模式,观察者模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式
其余:并发型模式和线程池模式
二:设计模式的六大准则
1、开闭准则(Open Close Principle)
开闭准则就是说 对扩大凋谢,对批改敞开 。在程序须要进行拓展的时候,不能去批改原有的代码,实现一个热插拔的成果。所以一句话概括就是:为了使程序的扩展性好,易于保护和降级。想要达到这样的成果,咱们须要应用接口和抽象类,前面的具体设计中咱们会提到这点。
2、里氏代换准则(Liskov Substitution Principle)
里氏代换准则 (Liskov Substitution Principle LSP) 面向对象设计的根本准则之一。里氏代换准则中说,任何基类能够呈现的中央,子类肯定能够呈现。LSP 是继承复用的基石,只有当衍生类能够替换掉基类,软件单位的性能不受到影响时,基类能力真正被复用,而衍生类也可能在基类的根底上减少新的行为。里氏代换准则是对“开 - 闭”准则的补充。实现“开 - 闭”准则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换准则是对实现抽象化的具体步骤的标准。
3、依赖倒转准则(Dependence Inversion Principle)
这个是开闭准则的根底,具体内容:真对接口编程,依赖于形象而不依赖于具体。
4、接口隔离准则(Interface Segregation Principle)
这个准则的意思是:应用多个隔离的接口,比应用单个接口要好。还是一个升高类之间的耦合度的意思,从这儿咱们看出,其实设计模式就是一个软件的设计思维,从大型软件架构登程,为了降级和保护不便。所以上文中屡次呈现:升高依赖,升高耦合。
5、迪米特法令(起码晓得准则)(Demeter Principle)
为什么叫起码晓得准则,就是说:一个实体该当尽量少的与其余实体之间产生相互作用,使得零碎功能模块绝对独立。
6、合成复用准则(Composite Reuse Principle)
准则是尽量应用合成 / 聚合的形式,而不是应用继承。
三:单例模式
1. 懒汉式(线程不平安)
懒汉式是用工夫换空间,不加同步是线程不平安
public class Singleton {
//2. 本类外部创建对象实例
private static Singleton instance=null;
/*
* 1. 构造方法私有化,内部不能 new*/
private Singleton(){}
//3. 提供一个私有的静态方法,返回实例对象
public static Singleton getInstance(){if (instance==null){instance=new Singleton();
}
return instance;
}
}
2. 懒汉式(线程平安)
增加一个 synchronized 同步关键字
public class Singleton {
//2. 本类外部创建对象实例
private static Singleton instance=null;
/*
* 1. 构造方法私有化,内部不能 new*/
private Singleton(){}
//3. 提供一个私有的静态方法,返回实例对象
public static synchronized Singleton getInstance(){if (instance==null){instance=new Singleton();
}
return instance;
}
}
3. 懒汉式(双重查看加锁,线程平安)
对象实例上增加一个 volatile 字段
public class Singleton {
//2. 本类外部创建对象实例
private volatile static Singleton instance=null;
/*
* 1. 构造方法私有化,内部不能 new*/
private Singleton(){}
//3. 提供一个私有的静态方法,返回实例对象
public static Singleton getInstance(){if (instance==null){synchronized (Singleton.class){if (instance==null){instance=new Singleton();
}
}
}
return instance;
}
}
4. 饿汉式
这种形式基于 classloder 机制防止了多线程的同步问题,不过,instance 在类装载时就实例化,尽管导致类装载的起因有很多种,在单例模式中大多数都是调用 getInstance 办法,然而也不能确定有其余的形式(或者其余的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的成果。
用空间换工夫,当类加载的时候就创立类的实例,不论你用不必,先创立进去
public class Singleton {
//2. 本类外部创建对象实例
private static Singleton instance=new Singleton();
/*
* 1. 构造方法私有化,内部不能 new*/
private Singleton(){}
//3. 提供一个私有的静态方法,返回实例对象
public static Singleton getInstance(){return instance;}
}
5. 饿汉式(变种,动态代码块)
动态代码块:用 staitc 申明,jvm 加载类时执行,仅执行一次
结构代码块:类中间接用 {} 定义,每一次创建对象时执行。
执行程序:动态代码块 >main()主办法 > 结构代码块 > 构造方法
public class Singleton {
//2. 本类外部创建对象实例
private static Singleton instance=null;
static {instance=new Singleton();// 即在类初始化实例化 instance
}
/*
* 1. 构造方法私有化,内部不能 new*/
private Singleton(){}
//3. 提供一个私有的静态方法,返回实例对象
public static Singleton getInstance(){return instance;}
}
6. 单例(动态外部类)
这种形式同样利用了 classloder 的机制来保障初始化 instance 时只有一个线程,它跟第四种和第五种形式不同的是(很轻微的差异):第四种和第五种形式是只有 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 成果),而这种形式是 Singleton 类被装载了,instance 不肯定被初始化。因为 SingletonHolder 类没有被被动应用,只有显示通过调用 getInstance 办法时,才会显示装载 SingletonHolder 类,从而实例化 instance。设想一下,如果实例化 instance 很耗费资源,我想让他提早加载,另外一方面,我不心愿在 Singleton 类加载时就实例化,因为我不能确保 Singleton 类还可能在其余的中央被被动应用从而被加载,那么这个时候实例化 instance 显然是不适合的。这个时候,这种形式相比第四种和第五种形式就显得很正当。
// 举荐这种写法
public class Singleton {
private static class SingletonHoler{
/*
* 2. 动态初始化器,由 JVM 来保障线程平安 */
private static final Singleton instance=new Singleton();}
/*
* 1. 构造方法私有化,内部不能 new*/
private Singleton(){}
//3. 提供一个私有的静态方法,返回实例对象
public static Singleton getInstance(){return SingletonHoler.instance;}
}
结尾:学而不思则罔,思而不学则殆