常用的设计模式汇总

设计模式合集23种设计模式,一个没少。比较常用的:单例、工厂、适配器、装饰者、代理、观察者这几个模式。其他的做个了解。单例模式作用:确保一个类只有一个实例,只对外提供一个访问该实例的全局访问点。特征:1、无法通过new得到实例,构造器是被private修饰的2、一般通过getInstance()的方法来获取它们的实例,而getInstance方法是对象的引用,并不是真正的new一个对象对于单例模式,又分为这几类饿汉式单例模式我的理解就是饿汉就是初始化就对对象加载,没有延时public c
摘要由CSDN通过智能技术生成

设计模式

在这里插入图片描述23种设计模式,一个没少。比较常用的:单例、工厂、适配器、装饰者、代理、观察者这几个模式。其他的做了解。

创建型模式

单例模式

作用:确保一个类只有一个实例,只对外提供一个访问该实例的全局访问点。
特征:
1、无法通过new得到实例,构造器是被private修饰的
2、一般通过getInstance()的方法来获取它们的实例,而getInstance方法是对象的引用,并不是真正的new一个对象
对于单例模式,又分为这几类

饿汉式单例模式
我的理解就是饿汉就是初始化就对对象加载,没有延时

public class SingletonDemo1 {
   
	
	//类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的是线程安全的!
	private static SingletonDemo1 instance = new SingletonDemo1();  
	
	private SingletonDemo1(){
   
	}
	
	//方法没有同步,调用效率高!
	public static SingletonDemo1  getInstance(){
   
		return instance;
	}
	
}

懒汉式加载(线程不安全)

public class Singleton {
   

  private static Singleton singleton;

  private Singleton() {
   
  }

  public static Singleton getInstance() {
   
   if (singleton == null) {
   
    singleton = new Singleton();
   }
   return singleton;
  }
}

懒汉式加载(线程安全)

public class SingletonDemo2 {
   
	
	//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
	private static SingletonDemo2 instance;  
	
	private SingletonDemo2(){
    //私有化构造器
	}
	
	//方法同步,调用效率低!
	public static  synchronized SingletonDemo2  getInstance(){
   
		if(instance==null){
   
			instance = new SingletonDemo2();
		}
		return instance;
	}
	
}

双重检查锁

注意:
双重检测锁式:涉及到JVM底层内部模型,偶尔会出问题。不建议使用

public class SingletonDemo3 {
    

  private volatile static SingletonDemo3 instance = null; 

  public static SingletonDemo3 getInstance() {
    
    if (instance == null) {
    
      SingletonDemo3 sc; 
      synchronized (SingletonDemo3.class) {
    
        sc = instance; 
        if (sc == null) {
    
          synchronized (SingletonDemo3.class) {
    
            if(sc == null) {
    
              sc = new SingletonDemo3(); 
            } 
          } 
          instance = sc; 
        } 
      } 
    } 
    return instance; 
  } 

  private SingletonDemo3() {
    

  } 
    
}

静态内部类
这个方法需要熟悉使用,很多用到单例的地方用这个方法就差不多可以了,优点:线程安全,调用效率高,并且实现了延时加载!

public class SingletonDemo4 {
   
	
	private static class SingletonClassInstance {
   
		private static final SingletonDemo4 instance = new SingletonDemo4();
	}
	
	private SingletonDemo4(){
   
	}
	
	//方法没有同步,调用效率高!
	public static SingletonDemo4  getInstance(){
   
		return SingletonClassInstance.instance;
	}
	
}

枚举实现单例模式

这个方法也很好地避免了多线程同步的问题,并且还能够反序列化重新创建对象。

public enum SingletonDemo5 {
   
	
	//这个枚举元素,本身就是单例对象!
	INSTANCE;

}

实际上,这里的单例模式并不是真正的单例,当出现反射和反序列化的时候就会变成原来的普通对象

反射测试

//懒汉测试类
public class SingletonDemo06 /*implements Serializable*/{
   

	
	private static SingletonDemo06 instace;
	
	private SingletonDemo06() {
   //需要私有化构造器

	}
	//方法需要同步,调用效率低
	public static synchronized SingletonDemo06 getInstace() {
   
		if(null == instace)
		{
   
			instace = new SingletonDemo06();
		}
		return instace;
	}

}

通过反射调用私有构造器

public static void main(String[] args) throws Exception, SecurityException {
   
		SingletonDemo06 s1 = SingletonDemo06.getInstace();
		SingletonDemo06 s2 = SingletonDemo06.getInstace();
		System.out.println(s1);
		System.out.println(s2);
		
		//通过反射的方式调用私有构造器
		Class<SingletonDemo06> clz = (Class<SingletonDemo06>) SingletonDemo06.class;
		Constructor<SingletonDemo06> cc = clz.getDeclaredConstructor();
		cc.setAccessible(true);
		SingletonDemo06 s3 = (SingletonDemo06)cc.newInstance();
		SingletonDemo06 s4 = (SingletonDemo06)cc.newInstance();
		System.out.println(s3);//Singleton.SingletonDemo06@2ff4acd0
		System.out.println(s4);//Singleton.SingletonDemo06@54bedef2
}

很显然反射后的对象跟单例的hashcode不一样
解决反射的方式
在私有构造器加一层判断

public class SingletonDemo06 /*implements Serializable*/{
   

	
	private static SingletonDemo06 instace;
	
	private SingletonDemo06() {
   //需要私有化构造器
		if(null != instace)
		{
   
			throw new RuntimeException();//防止反射下创建新的对象
		}
	}
	//方法需要同步,调用效率低
	public static synchronized SingletonDemo06 getInstace() {
   
		if(null == instace)
		{
   
			instace = new SingletonDemo06();
		}
		return instace;
	}

}

反序列化Demo

	public static void main(String[] args) throws Exception, SecurityException {
   
		SingletonDemo06 s1 = SingletonDemo06.getInstace();
		SingletonDemo06 s2 = SingletonDemo06.getInstace();
		System.out.println(s1);//Singleton.SingletonDemo06@279f2327
		System.out.println(s2);//Singleton.SingletonDemo06@279f2327
		
		//通过反射的方式调用私有构造器
//		Class<SingletonDemo06> clz = (Class<SingletonDemo06>) SingletonDemo06.class;
//		Constructor<SingletonDemo06> cc = clz.getDeclaredConstructor();
//		cc.setAccessible(true);
//		SingletonDemo06 s3 = (SingletonDemo06)cc.newInstance();
//		SingletonDemo06 s4 = (SingletonDemo06)cc.newInstance();
//		System.out.println(s3);//Singleton.SingletonDemo06@2ff4acd0
//		System.out.println(s4);//Singleton.SingletonDemo06@54bedef2
		
		//通过反序列化的方式构造多个对象
		FileOutputStream fos = new FileOutputStream("d:/a.txt");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(s1);
		oos.close();
		fos.close();
		
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt"));
		SingletonDemo06 s3 =  (SingletonDemo06) ois.readObject();
		System.out.println(s3);//Singleton.SingletonDemo06@26a1ab54
	}

解决方法readResolve()直接返回指定的单例对象

public class SingletonDemo06 implements Serializable{
   

	
	private static SingletonDemo06 instace;
	
	private SingletonDemo06() {
   //需要私有化构造器
		if(null != instace)
		{
   
			throw new RuntimeException();//防止反射下创建新的对象
		}
	}
	//方法需要同步,调用效率低
	public static synchronized SingletonDemo06 getInstace() {
   
		if(null == instace)
		{
   
			instace = new SingletonDemo06();
		}
		return instace;
	}

	//反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象!
	private Object readResolve() throws Exception{
   
		return instace;
	}
}

总结:
单例模式的优点:
1、单例模式只产生一个实例,减少了性能的开销
2、当一个对象需要很多资源的时候,例如读取配置、产生依赖等,可以直接在启动时产生单例,让他永久驻留内存
3、单例可以让全局使用,达到优化资源共享

五种单例模式的实现方式比较:

  1. 饿汉式:线程安全,调用效率高。 但是,不能延时加载
  2. 懒汉式:线程安全,调用效率不高。 但是,可以延时加载
  3. 双重检测锁式:由于JVM底层内部模型原因,偶尔会出问题。不建议使用
  4. 静态内部类式:线程安全,调用效率高。 但是,可以延时加载
  5. 枚举单例:线程安全,调用效率高,不能延时加载
    效率测试

单例模式的应用:
1、Windows的Task Manager(任务管理器)、回收站就是很典型的单例模式
2、 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作 ,否则内容不好追加。
3、spring容器的管理

工厂模式

主要是为了实现创建者和调用者的分离。通过工厂的方法代替new实例化对象,将实现类、创建对象统一管理和控制,达到调用者与实现者的解耦合。

简单工厂模式
一个抽象的接口,多个抽象接口的实现类,一个工厂类。弊端:一般是静态方法,对新增加的类必须修改代码。

public intereface Car{
   
	void run();
}
public class Audi implements Car {
   
	@Override
	public void run() {
   
		System.out.println("奥迪生产");
	}
}
public class byd implements Car{
   
	@Override
	public void run() {
   
		System.out.println("比亚迪生产");
	}
  • 10
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值