单例模式(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
前加了一个修饰词volative
,volatile
保证了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 抽象工厂