首页 > 代码库 > 单例模式和工厂方法模式
单例模式和工厂方法模式
单例模式的定义
单例模式(Singleton Pattern)是一个比较简单的模式,其定义如下:
Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)
单例模式通用代码
public class Singleton {
private static final Singleton singleton = new Singleton();
//限制产生多个对象
private Singleton(){
}
//通过该方法获得实例对象
public static Singleton getSingleton(){
return singleton;
}
//类中其他方法,尽量是static
public static void doSomething(){
HuDun Demo
}
}
单例模式的优点
● 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地
创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
● 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要
比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一
个单例对象,然后用永久驻留内存的方式来解决(在Java EE中采用单例模式时需要注意JVM
垃圾回收机制)。
● 单例模式可以避免对资源的多重占用。
● 单例模式可以在系统设置全局的访问点,优化和共享资源访问。
单例模式的缺点
● 单例模式一般没有接口,扩展很困难。
● 单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行
测试的,没有接口也不能使用mock的方式虚拟一个对象。
● 单例模式与单一职责原则有冲突。
单例模式的使用场景
在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反
应”,可以采用单例模式,具体的场景如下:
● 要求生成唯一序列号的环境;
● 在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以
不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
● 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
● 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当
然,也可以直接声明为static的方式)。
单例模式的注意事项
首先,在高并发情况下,请注意单例模式的线程同步问题。
其次,需要考虑对象的复制情况。在Java中,对象默认是不可以被复制的,若实现了
Cloneable接口,并实现了clone方法,则可以直接通过对象复制方式创建一个新对象,对象
复制是不用调用类的构造函数,因此即使是私有的构造函数,对象仍然可以被复制。
注意:
需要产生固定数量对象的模式就叫做有上限的多例模式,它是单例模式的一种扩
展,采用有上限的多例模式,我们可以在设计时决定在内存中有多少个实例,方便系统进行
扩展,修正单例可能存在的性能问题,提供系统的响应速度。
工厂方法模式的定义
工厂方法模式使用的频率非常高,在我们日常的开发中总能见到它的身影。其定义为:
Define an interface for creating an object,but let subclasses decide which class to
instantiate.Factory Method lets a class defer instantiation to subclasses.(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。)
工厂方法模式的优点
首先,良好的封装性,代码结构清晰。
其次,工厂方法模式的扩展性非常优秀。
最后,工厂方法模式是典型的解耦框架。
工厂方法模式的使用场景
首先,工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用。
其次,需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。
再次,工厂方法模式可以用在异构项目中。
最后,可以使用在测试驱动开发的框架下。
工厂方法模式的扩展
1. 缩小为简单工厂模式
简单工厂模式(Simple Factory Pattern),也叫做
静态工厂模式。在实际项目中,采用该方法的案例还是比较多的,其缺点是工厂类的扩展比
较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式。
2. 升级为多个工厂类
3. 替代单例模式
单例模式的核心要求就是在内存中只有一个对象,通过工厂方法模式也可以只在内存中生产一个对象。
4. 延迟初始化
何为延迟初始化(Lazy initialization)?一个对象被消费完毕后,并不立刻释放,工厂类
保持其初始状态,等待再次被使用。延迟初始化是工厂方法模式的一个扩展应用。
延迟加载的工厂类
public class ProductFactory {
private static final Map<String,Product> prMap = new HashMap();
public static synchronized Product createProduct(String type) throws Exception{
Product product =null;
//如果Map中已经有这个对象
if(prMap.containsKey(type)){
product = prMap.get(type);
}else{
if(type.equals("Product1")){
product = new ConcreteProduct1();
}else{
product = new ConcreteProduct2();
HuDun Demo
}
//同时把对象放到缓存容器中
prMap.put(type,product);
}
return product;
}
}
代码还比较简单,通过定义一个Map容器,容纳所有产生的对象,如果在Map容器中已
经有的对象,则直接取出返回;如果没有,则根据需要的类型产生一个对象并放入到Map容
器中,以方便下次调用。
单例模式和工厂方法模式