设计模式之单例
2019-08-05 本文已影响0人
云木杉
定义 确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
- 单例模式核心就是将构造函数私有化,并且通过静态方法获取一个唯一的实例,在这个获取的过程中你必须保证线程安全、反序列化导致重新生成实例对象等问题,该模式简单,但使用率较高。、
import java.util.ArrayList;
import java.util.List;
public class SingleTest {
public static void main(String[] args) {
Company cp = new Company() ;
Person ceo1 = Ceo.getSiCeo() ;
Person ceo2 = Ceo.getSiCeo() ;
cp.addStaff(ceo1);
cp.addStaff(ceo2);
Person vp1 = new VP() ;
Person vp2 = new VP() ;
cp.addStaff(vp1);
cp.addStaff(vp2);
Person staff1 = new Staff() ;
Person staff2 = new Staff() ;
Person staff3 = new Staff() ;
cp.addStaff(staff1);
cp.addStaff(staff2);
cp.addStaff(staff3);
cp.showAllStaffs();
}
}
abstract class Person{
abstract void talk();
}
class Staff extends Person{
@Override
void talk() {
// TODO Auto-generated method stub
System.out.println("普通员工");
}
}
class VP extends Person{
@Override
void talk() {
// TODO Auto-generated method stub
System.out.println("副总裁");
}
}
class Ceo extends Person{
private static final Ceo mCeo = new Ceo();
public static Ceo getSiCeo() {
return mCeo;
}
@Override
void talk() {
// TODO Auto-generated method stub
System.out.println("CEO");
}
}
class Company {
private List<Person> allPersons = new ArrayList<Person>();
public void addStaff(Person per) {
allPersons.add(per);
}
public void showAllStaffs() {
for (Person per : allPersons) {
System.out.println("Obj : " + per.toString());
}
}
}
单例模式的其他实现
package com.dp.example.singleton;
public class Singleton {
private static Singleton mInstance = null;
private Singleton() {
}
public void doSomething() {
System.out.println("do sth.");
}
/**
* 方式二、double-check, 避免并发时创建了多个实例, 该方式不能完全避免并发带来的破坏.
* 同时进来A B 线程进行实例化
* @return
*/
public static Singleton getInstance() {
//1 判断 线程是否为null A进去了
if (mInstance == null) {
//2 A进去以后 加锁 堵塞B线程
// 5 A释放线程 B进入
synchronized (Singleton.class) {
//3 判断为null A进入 实例化
// 6 判断实例不为null 直接返回
if (mInstance == null) {
//4 A实例化成功
mInstance = new Singleton();
}
}
}
return mInstance;
}
/**
* 方式三 : 在第一次加载SingletonHolder时初始化一次mOnlyInstance对象, 保证唯一性, 也延迟了单例的实例化,
* 如果该单例比较耗资源可以使用这种模式.
*
* @return
*/
public static Singleton getInstanceFromHolder() {
return SingletonHolder.mOnlyInstance;
}
/**
* 静态内部类
*
* @author mrsimple
*
*/
private static class SingletonHolder {
private static final Singleton mOnlyInstance = new Singleton();
}
/**
* 方式四 : 枚举单例, 线程安全
* @author mrsimple
*
*/
enum SingletonEnum {
INSTANCE;
public void doSomething() {
System.out.println("do sth.");
}
}
/**
* 方式五 : 注册到容器, 根据key获取对象.一般都会有多种相同属性类型的对象会注册到一个map中
* instance容器
*/
private static Map<string singleton=""> objMap = new HashMap<string singleton="">();
/**
* 注册对象到map中
* @param key
* @param instance
*/
public static void registerService(String key, Singleton instance) {
if (!objMap.containsKey(key) ) {
objMap.put(key, instance) ;
}
}
/**
* 根据key获取对象
* @param key
* @return
*/
public static Singleton getService(String key) {
return objMap.get(key) ;
}
}
优点与缺点
优点
- 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
- 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决;
- 单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
- 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
缺点
- 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。