设计模式之单例和模板

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/michael_yt/article/details/81568055

单例模式

核心思想就是,构造函数私有化,通过静态方法获取唯一实例并保证线程安全,防止反序列化重新生成实例。

饿汉式

public class Singleton {
    private static final Singleton mSingleton = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return mSingleton;
    }
}

第一次声明的时候实例化,后续通过getInstance得到唯一的实例,速度快,但是线程不安全。

懒汉式

public class Singleton {
    private static  Singleton mSingleton ;
    private Singleton(){}
    public static synchronized Singleton getInstance(){
        if (mSingleton==null){
            mSingleton=new Singleton();
        }
        return mSingleton;
    }
}

使用的时候实例化,通过synchronized保证了线程安全,但是每次获取实例都会进行同步,资源消耗大。

Double Check Lock(DCL)

public class Singleton {
    private volatile static Singleton mSingleton = null;
    private Singleton(){}
    public static Singleton getInstance() {
        if (mSingleton==null) {
            synchronized (Singleton.class) {
                if (mSingleton==null) {
                    mSingleton=new Singleton();
                }
            }
        }
        return mSingleton;
    }
}

在懒汉式的基础上做了优化,对实例进行了两次null判断,避免了每次获取实例都同步,并且加入了volatile关键字,保证了都是从主内存中获取对象,大部分都是用这种模式

静态内部类

public class Singleton {
    private Singleton(){}
    public static  Singleton getInstance(){
        return SingletonHolder.mSingleton;
    }
    private static class SingletonHolder{
        private static final Singleton mSingleton = new Singleton();
    }
}

当第一次加载Singleton的时候并不会初始化mSingleton,只有在第一次调用getInstance的时候才会加载SIngletonHolder类。不仅能保证线程安全,也能保证单例的唯一性,也延迟了单例的实例化,比较推荐

枚举单例

public enum Singleton{
    INSTANCE;
    public void doThing(){
        System.out.println(this.hashCode());
    }
}

使用时可以通过Singleton singleton = Singleton.INSTANCE;来获取单例。写法简单,而且默认线程安全,任何情况下都是一个单例。

防止反序列化导致新建实例

public class Singleton {
    private Singleton(){}
    public static  Singleton getInstance(){
        return SingletonHolder.mSingleton;
    }
    private static class SingletonHolder{
        private static final Singleton mSingleton = new Singleton();
    }

    private Object readRedolve() throws ObjectStreamException{  //通过添加这个方法实现
        return SingletonHolder.mSingleton;
    }
}

使用容器实现单例

public class SingletonManager {
    private static Map<String,Objects> objMap = new HashMap<>();
    private SingletonManager(){}
    public static void registerService(String key,Object obj){
        if (!objMap.containsKey(key)){
            objMap.put(key,obj);
        }
    }
    public static Object getService(String key){
        return objMap.get(key);
    }
}

在程序的开始,将许多要单例的对象放到一个容器里,用的时候根据key取得对应的单例对象。

优点:很多
缺点:1.不能扩展 2.单例模式如果持有context容易引起内存泄露,应该传入Application Context.

模板方法模式

核心思想就是,抽象父类定义几个操作函数并通过final定义一个整合这几个函数的算法方法,子类通过继承抽象父类并重写其中的一个或者多个操作函数,最后执行final方法,从而达到不改变算法步骤,但是改变具体执行方法的效果。

package com.dp.example.templatemethod;
/**
 * 抽象父类Computer
 * @author mrsimple
 *
 */
public abstract class AbstractComputer {

    protected void powerOn() {  //注意不是抽象借口
        System.out.println("开启电源");
    }

    protected void checkHardware() {
        System.out.println("硬件检查");
    }

    protected void loadOS() {
        System.out.println("载入操作系统");
    }

    protected void login() {
        System.out.println("小白的电脑无验证,直接进入系统");
    }

    /**
     * 启动电脑方法, 步骤固定为开启电源、系统检查、加载操作系统、用户登录。该方法为final, 防止算法框架被覆写.
     */
    public final void startUp() {
        System.out.println("------ 开机 START ------");
        powerOn();
        checkHardware();
        loadOS();
        login();
        System.out.println("------ 开机 END ------");
    }
}


package com.dp.example.templatemethod;

/**
 * 码农的计算机
 * 
 * @author mrsimple
 */
public class CoderComputer extends AbstractComputer {
    @Override
    protected void login() { //子类重写
        System.out.println("码农只需要进行用户和密码验证就可以了");
    }
}


package com.dp.example.templatemethod;

/**
 * 军用计算机
 * 
 * @author mrsimple
 */
public class MilitaryComputer extends AbstractComputer {


    @Override
    protected void checkHardware() {
        super.checkHardware();
        System.out.println("检查硬件防火墙");
    }

    @Override
    protected void login() {
        System.out.println("进行指纹之别等复杂的用户验证");
    }
}

 //使用
package com.dp.example.templatemethod;

public class Test {
    public static void main(String[] args) {
        AbstractComputer comp = new CoderComputer(); //新建一个CoderComputer子类对象
        comp.startUp(); //执行final算法方法

        comp = new MilitaryComputer();  //新建MilitaryComputer子类对象
        comp.startUp();  //执行final算法方法

    }

优点:1.对流程的封装,封装不变部分,扩展可变部分 2.提取公共部分代码,便于维护
缺点:不利于代码阅读

参考 《Android源码设计模式解析与实战》 — 何红辉 关爱民

猜你喜欢

转载自blog.csdn.net/michael_yt/article/details/81568055