单例模式(Singleton)

要求单例类最多只能有一个实例对象

最简单的实现是,在单例类内保存静态实例对象,并将构造方法生命为private的,防止调用者构造新对象

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

这种实现已经足够满足‘单例’的要求了,但存在一个问题,当第一次加载Singleton类的时候,其实例对象就生成了,并且一直存活到类被回收(类的Class对象是放在JVM的方法区的,方法区也称Permonent Area,回收频率是很低的),这当单例类比较大或内存吃紧的时候,代价是比较高昂的!

一个简单的改进是延迟对象的生成,比如当第一次用到实例对象的时候才去构造对象

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

这样虽然可以延迟对象的生成时间,但却引发了一个问题:线程安全!

考虑多个线程同时访问getInstance()方法时,就可能会生成多个对象,这就不再‘单例’了

如果程序不存在多线程问题,那么这个方案已经非常好了,但并发编程是非常普遍的,还需要改进这个设计

为了实现线程安全,最简单的方法就是在方法上加上synchronized的关键字

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

这种方式有效,但有点‘粗暴’:如果该实例访问比较频繁的话,synchronized整个方法会带来巨大的性能损失

继续改进,其实并不是每次访问都需要synchronized:如果instance早就实例化了,那么直接返回不就好了么!

class Singleton{
    private static volatile Singleton instance;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instance==null){ // 只有instance还没有实例化的时候才需要进入synchronized区域
            synchronized(Singleton.class){
                if(instance==null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

如代码中的注释部分,只有当instance为空的时候才synchronized对象创建过程

注意,这里instance前加了一个修饰词volativevolatile保证了instance的可见性,具体参考这里

上面这种方式已经很好了,但还是存在并发处理,有一种结合工厂方法的做法很取巧:

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

参考: 单例模式的几种实现

工厂模式

该部分是来自《Head First 设计模式》的读书笔记,所以代码实例也出自那里

工厂类的主要目的就是将实例化类的代码从应用中抽里出来,或者封装起来

最简单的方法就是使用所谓的‘简单工厂’模式:简单粗暴地将创建对象的代码封装到一个‘工厂’类中,之后在需要创建对象的地方,引入该工厂即可

// 简单工厂 
public class SimplePizzaFactory {  
  
    // 这里的`createPizza`方法是成员方法,可以用来继承重写,如果不考虑多态,可以直接设成静态的
    public Pizza createPizza(String type) {  
        Pizza pizza = null;  
  
        if (type.equals("cheese")) {  
            pizza = new CheesePizza();  
        } else if (type.equals("pepperoni")) {  
            pizza = new PepperoniPizza();  
        } else if (type.equals("clam")) {  
            pizza = new ClamPizza();  
        } else if (type.equals("veggie")) {  
            pizza = new VeggiePizza();  
        }  
        return pizza;  
    }  
}

// 商店类,需要使用工厂方法
public class PizzaStore {  
    SimplePizzaFactory factory;  
   
    public PizzaStore(SimplePizzaFactory factory) {   
        this.factory = factory;  
    }  
   
    public Pizza orderPizza(String type) { 
        Pizza pizza;  
   
        pizza = factory.createPizza(type);
   
        pizza.prepare();  
        pizza.bake();  
        pizza.cut();  
        pizza.box();  
  
        return pizza;  
    }  
}

上面就完成了对创建对象的封装,可以创建各种各样的’pizza’,但这里有个问题,比如所有的PizzaStore都使用同一个工厂,得到全都相同的pizza,失去了定制性!

为了赋予不同的‘PizzaStore’不同的定制‘Pizza’的权限,使用工厂方法模式:

// 注意,这里类是抽象类
public abstract class PizzaStore {  
    // 工厂方法,注意这里是abstract,要求子类必须实现
    abstract Pizza createPizza(String item);  
   
    public Pizza orderPizza(String type) {  
        Pizza pizza = createPizza(type);  
        System.out.println("--- Making a " + pizza.getName() + " ---");  
        pizza.prepare();  
        pizza.bake();  
        pizza.cut();  
        pizza.box();  
        return pizza;  
    }  
}

public class NYPizzaStore extends PizzaStore {  
    Pizza createPizza(String item) {  
        // implements customized method
    }  
}

public class BJPizzaStore extends PizzaStore {  
    Pizza createPizza(String item) {  
        // implements customized method
    }  
}

TODO 抽象工厂

TOP