什么是设计模式?
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。通俗的说:设计模式是前辈、大牛在实际编程中对遇到的问题解决方案的抽象。
设计模式的分类
总体来说设计模式分为三大类:
创建型模式,共五种:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
在这里我们重点的说一下常用的一些设计模式。
单例模式
在我们开发中会经常用到单例模式,例如建立目录、数据库连接的单线程操作;某个需要被频繁访问的实例对象;Android网络框架的实现类等。
单例模式保证一个类只有一个实例存在,并提供一个可以访问它的全局访问点。这样做的好处就是减少内存开销,同时也可以避免对资源的多重占用。
单例模式有多重写法,下面我们就列举下最常用的几种:
1.饿汉模式
public class Singleton {
/**
* 饿汉模式
*/
private static Singleton instance = new Singleton();
private Singleton (){
}
public static Singleton getInstance() {
return instance;
}
}
这种方式是在类加载过程中就完成初始化操作,会影响类的加载速度,但是获取对象的速度快。
2.懒汉模式(非线程安全)
public class Singleton {
/**
* 懒汉模式(非线程安全)
*/
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉模式申明一个静态对象,在用户第一次调用getInstance()时初始化对象,虽然节约资源,但第一次加载时需要实例化,会影响加载速度,而且在多线程不能正常工作。
3.懒汉模式(线程安全)
/**
* 懒汉模式(线程安全)
*/
private static Singleton instance;
private Singleton (){
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种模式可以很好的在多线程中工作,但是每次调用getInstance()都需要进行同步,而且日常开发中基本上不会用到同步。因此不推荐这种写法。
4.双重检查模式 (DCL)
/**
* 双重检查模式
*/
private volatile static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance== null) {
synchronized (Singleton.class) {
if (instance== null) {
instance= new Singleton();
}
}
}
return instance;
}
}
这种方式在getInstance()方法中对instance进行了两次判空,第一次是为了不必要的同步,第二次是在instance等于null的情况下才创建实例。DCL优点是资源利用率高,第一次执行getInstance()时单例对象才被实例化,效率高。缺点是第一次加载时反应稍慢一些,在高并发环境下也有一定的缺陷,虽然发生的概率很小。DCL虽然在一定程度解决了资源的消耗和多余的同步,线程安全等问题,但是他还是在某些情况会出现失效的问题,也就是DCL失效,在《java并发编程实践》一书建议用静态内部类单例模式来替代DCL。
5.静态内部类单例模式
/**
* 静态内部类单例模式
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
第一次加载Singleton类时并不会初始化sInstance,只有第一次调用getInstance方法时虚拟机加载SingletonHolder 并初始化sInstance ,这样不仅能确保线程安全也能保证Singleton类的唯一性,推荐使用静态内部类单例模式。
6.使用容器实现单例模式
public class SingletonManager {
private static Map<String, Object> objMap = new HashMap<>();
private SingletonManager() {
}
public static void registerService(String key, Object instance) {
if (!objMap.containsKey(key)) {
objMap.put(key, instance);
}
}
public static Object getService(String key) {
return objMap.get(key);
}
}
用SingletonManager 将多种的单例类统一管理,在使用时根据key获取对象对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。
未完待续……