GOF 23设计模式之一(创建型模式)

目录

1.单例模式

1.1饿汉模式

1.2懒汉模式

1.3其他单例模式

2.原型模式

2.1 浅克隆

2.2深克隆



一、单例模式(Singleton)

      保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

      优点:由于只生成一个实例,减少了系统性能开销。可以在系统中设置全局的访问点,优化环境共享资源访问。如:可以设置一个单例类,负责所有数据表的映射处理。

      常见的单例模式:

  • 饿汉模式(线程安全,调用效率高,不能延迟加载)(主要)
  • 懒汉模式(线程安全,调用效率不高,可以延迟加载)(主要)
  • 双重检测锁(由于JVM底层内部模型原因,偶尔会出现问题,不推荐使用)
  • 静态内部类式(线程安全,调用效率高,可以延迟加载)
  • 枚举单例(线程安全,调用效率高,不能延迟加载)

      单例模式UML图:

在这里插入图片描述

(1) 饿汉模式

      问题:

  1. 如果只是加载本类、不调用本类的getInstance()方法,或永远不调用本类。就会造成资源的浪费。
  2. 线程安全,反射,反序列化,是不安全的。
class eh{
    
    private static final eh texteh = new eh(); //(1)直接创建私有实例对象
    private eh() {}   //(2)私有无参的构造函数
    
    public static eh getInstance() { //(3)唯一一个公用的调用实例的方法
        return texteh;
    }
}

      为了防止序列化、反序列化对单例模式的破坏。可以使用下面方法,指定返回的是同一个对象。

private Object readResolve(){
	return texteh;
}

返回顶部

(2) 懒汉模式

      问题:资源利用效率高了。但是,每次调用getInstance()方法都要同步,并发效率较低。

class lh{
   
    private static volatile lh textlh = null;//(1)使用volatile保证所有线程安全
    private lh() {} //(2)私有无参构造
   
    public static synchronized lh getInstance() { //(3)添加同步synchronized 
        
        //如果是第一次调用的,就创建。否则,使用原来创建的
        if(textlh == null) {
            textlh = new lh();
        }
        return textlh;
    }
}

      也可以使用同步代码块(效率比较低)

 public static lh getInstance() { //(3)添加同步synchronized 
        synchronized(lh.class){
        //如果是第一次调用的,就创建。否则,使用原来创建的
        if(textlh == null) {
            textlh = new lh();
        }
        }
        return textlh;
    }

返回顶部

(3)其他单例模式
  1. 双重检测锁:提高了利用效率,不必每一次都需要进行同步。只是同步第一次。其他的都不用同步。
class scjc{
    
    private static scjc jc = null;
    private scjc() {}
    
    private static scjc getInstance() {
        
        if(jc == null) {
            scjc jcs;
            synchronized (scjc.class) {
                jcs = jc;
                if(jcs == null) {
                    synchronized (scjc.class) {
                        if(jcs == null) {
                            jcs = new scjc();
                        }
                    }
                }
            }
        }
        return jc;
    }
}
  1. 静态内部类:静态内部类不会立即加载,只要调用了getInstance()方法才会加载。tt的加载只会创建一次,只能被赋值一次,保证了线程的安全。兼备了高并发调用和延迟加载的优势。
    线程安全,防止反射攻击,反序列化不安全。
class text{
    
    private static class text2{ //静态内部类
    private static final text tt = new text();
    }
  
    private text() {} //私有无参构造
    
    public static text getInstance(){
        return text2.tt;
    }
}

      为了防止反射的破坏,在私有构造器里面可以进行一个判断,检测对象的实例化。

 private text() {
	if(text2.tt != null){
	throw new IllegalStateException();
}
}
  1. 枚举实现类式:枚举本身就是一个单例模式,有JVM的保障,避免了通过反射和反序列化的漏洞。
    线程安全、支持序列化、反序列化安全,防止反射攻击。
public enum text {

    tt; //直接调用,就可以获取单例对象
    
    //添加自己的方法
    public void getOther() {}
}

返回顶部

二、原型模式(Prototype)

      将一个对象作为原型,克隆复制出多个和原型类似的新实例。克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出来的对象属性和原型的完全一样,并且改变新克隆出来的对象不会影响原型对象。克隆的实现需要实现Cloneable接口和重写clone方法。克隆出来的是一个新的对象,不是单例。

      克隆分为深克隆、浅克隆。

      核心角色:

  • (1)抽象原型类:规定抽象原型对象必须实现的接口(Cloneable)
  • (2)具体原型类:实现抽象原型类的clone方法,它是可被复制的
  • (2)访问类:使用具体原型类中的clone方法来复制新的对象

1、浅克隆:

      浅克隆克隆的不是全部的原型,如果原型在克隆的过程中被修改了。那么克隆的是修改后的东西

public class text implements Cloneable{
    
    private String name;

    public text(String name) {
        super();
        this.name = name;
    }
    //补全get、set方法

    @Override
    protected Object clone() throws CloneNotSupportedException {

        return (text)super.clone();//浅克隆
    }
    
    public static void main(String[] args){
        
        text tt = new text("huang");
        text clone = (text) tt.clone();//克隆
        
        tt.setName("ling"); //克隆的时候被修改了属性
        
        System.out.println(tt.getName());
        System.out.println(clone.getName());    
    }
}

返回顶部

2、深克隆

      深克隆的是对整个对象进行克隆。就算在克隆途中改变了属性,也不会影响克隆体。

public class text implements Cloneable{
    
    private String name;
    private Date date;

    public text(String name,Date date) {
        super();
        this.name = name;
        this.date = date;
    }
    //补全get、set方法

    @Override
    protected Object clone() throws CloneNotSupportedException {
        
        Object obj = super.clone();
        text tt = (text)obj;
        
        tt.name = (String)this.name; //如果是一般数据类型。
        tt.date = (Date)this.date.clone();//其他类型

        return obj;//浅克隆
    }
    
    public static void main(String[] args) throws CloneNotSupportedException {
        
        text tt = new text("huang",new Date(2020,1,3));
        text clone = (text) tt.clone();//克隆
        
        tt.setName("ling");    //属性被修改
        tt.setDate(new Date(2020,1,2));
        
        System.out.println(tt.getName()+","+tt.getDate());
        System.out.println(clone.getName()+","+clone.getDate());    
    }
}

返回顶部

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值