创建型模式【3】——原型模式

 


1 原型模式特点

  • 定义 : 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
  • 特点 : 不需要知道任何创建的细节,不调用构造函数
  • 类型 : 创建型

适用场景

  • 类初始化消耗较多资源
  • new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
  • 构造函数比较复杂
  • 循环体中生产大量对象时
  • 优点 : 原型模式性能比直接new一个对象性能高,简化创建过程
  • 缺点 : 必须配备克隆方法,对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险,深拷贝、浅拷贝要运用得当

2 Coding

现在有一只羊tom(姓名:tom、年龄:1、颜色:白色),请编写程序创建和tom羊属性完全相同的10只羊

 传统的方法

@Data
public class Sheep {
    // 名字
    private String name;
    // 年龄
    private int age;
    // 颜色
    private String color;
    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
}
@Test
public void test() {
    //传统的方法
    Sheep sheep = new Sheep("tom", 1, "白色");
    Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
    Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
    Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
    Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
    //....
    System.out.println(sheep);
    System.out.println(sheep2);
    System.out.println(sheep3);
    System.out.println(sheep4);
    System.out.println(sheep5);
    //...
}

实现Cloneable

@Data
// 实现Cloneable
public class Sheep implements Cloneable{
    private String name;
    private int age;
    private String color;
    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
    // 重写clone
    @Override
    protected Sheep clone() throws CloneNotSupportedException {
        // 使用默认的clone方法来完成
        return (Sheep)super.clone();
    }
}
@Test
public void test() throws CloneNotSupportedException {
    System.out.println("原型模式完成对象的创建");
    Sheep sheep = new Sheep("tom", 1, "白色");
    Sheep sheep2 = sheep.clone(); //克隆
    Sheep sheep3 = sheep.clone(); //克隆
    Sheep sheep4 = sheep.clone(); //克隆
    Sheep sheep5 = sheep.clone(); //克隆
    System.out.println("sheep2 =" + sheep2);
    System.out.println("sheep3 =" + sheep3);
    System.out.println("sheep4 =" + sheep4);
    System.out.println("sheep5 =" + sheep5);
}

 

//抽象类
public abstract class A implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class B extends A {
    public static void main(String[] args) throws CloneNotSupportedException {
        B b = new B();
        B clone = (B) b.clone();
        System.out.println(b); // B@6ff3c5b5
        System.out.println(clone); // B@3764951d
    }
}

3 原型模式扩展

3.1 浅克隆错误演示

@Data
public class Pig implements Cloneable {
    private String name;
    private Date birthday;
    public Pig(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
@Test
public void test() throws CloneNotSupportedException {
    Date birthday = new Date(0L);
    Pig pig = new Pig("佩奇", birthday);
    Pig cPig = (Pig) pig.clone();
    System.out.println(pig);                    // Pig(name=佩奇, birthday=Thu Jan 01 08:00:00 CST 1970)
    System.out.println(cPig);                   // Pig(name=佩奇, birthday=Thu Jan 01 08:00:00 CST 1970)
    //本意只是修改pig的生日
    pig.getBirthday().setTime(666666666666L);
    System.out.println(pig);                    // Pig(name=佩奇, birthday=Sat Feb 16 09:11:06 CST 1991)
    //cPig也改了,这个结果不是我想要的,原因出在浅拷贝上
    System.out.println(cPig);                   // Pig(name=佩奇, birthday=Sat Feb 16 09:11:06 CST 1991)
}

3.2 深克隆两种实现方式

@Data
public class Pig implements Cloneable, Serializable {
    private static final long serialVersionUID = 779970270042384579L;
    private String name;
    private Date birthday;
    public Pig(String name, Date birthday) {this.name = name;this.birthday = birthday;}
    // 1、深拷贝——使用clone方法
    //Remove this "clone" implementation; use a copy constructor or copy factory instead.
    @Override
    protected Pig clone() throws CloneNotSupportedException {
        Pig pig = (Pig) super.clone();
        pig.birthday = (Date) pig.birthday.clone();
        return pig;
    }
    // 2、深拷贝——通过对象的序列化实现 (推荐)
    public Pig deepClone() {
        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); //当前这个对象以对象流的方式输出
            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            return (Pig) ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e) {}
        }
    }
}
@Test
public void test() {
    Date birthday = new Date(0L);
    Pig pig = new Pig("佩奇", birthday);
    //Pig cPig = pig.clone();
    Pig cPig = pig.deepClone();
    System.out.println(pig);                // Pig(name=佩奇, birthday=Thu Jan 01 08:00:00 CST 1970)
    System.out.println(cPig);               // Pig(name=佩奇, birthday=Thu Jan 01 08:00:00 CST 1970)
    pig.getBirthday().setTime(666666666666L);
    System.out.println(pig);                // Pig(name=佩奇, birthday=Sat Feb 16 09:11:06 CST 1991)
    System.out.println(cPig);               // Pig(name=佩奇, birthday=Thu Jan 01 08:00:00 CST 1970)
}


4 原型模式破坏单例模式

单例模式实现了Cloneable一定要小心

//实现Serializable和Cloneable接口
public class Singleton implements Cloneable {
    private final static Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return instance;
    }
    @Override
    protected Singleton clone() {
        //return (Singleton) super.clone();
        //注意,返回的是静态变量,不要调用父类方法然后返回
        return instance;
    }
}
/**
 * 原型模式里面的克隆可能会破坏单例模式
 */
@Test
public void test() throws Exception {
    Singleton hungrySingleton = Singleton.getInstance();
    Singleton cloneHungrySingleton = hungrySingleton.clone();
    System.out.println(hungrySingleton);//
    System.out.println(cloneHungrySingleton);//
}

5 源码分析 

public class HungrySingleton implements Serializable, Cloneable {
    private final static HungrySingleton hungrySingleton;
    static {
        hungrySingleton = new HungrySingleton();
    }
    private HungrySingleton() {
        if (hungrySingleton != null) {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }
    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }
    private Object readResolve() {
        return hungrySingleton;
    }
    //
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return getInstance();
    }
}
@Test
public void test() throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    HungrySingleton hungrySingleton = HungrySingleton.getInstance();
    Method method = hungrySingleton.getClass().getDeclaredMethod("clone");
    method.setAccessible(true);
    HungrySingleton cloneHungrySingleton = (HungrySingleton) method.invoke(hungrySingleton);
    System.out.println(hungrySingleton);//HungrySingleton@66cd51c3
    System.out.println(cloneHungrySingleton);//HungrySingleton@66cd51c3
}

https://www.jianshu.com/p/54b0711a8ec8 

//java.lang.Cloneable
public interface Cloneable {

//java.util.ArrayList
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
//<dependency>
//    <groupId>org.mybatis</groupId>
//    <artifactId>mybatis</artifactId>
//    <version>3.5.4</version>
//</dependency>

//org.apache.ibatis.cache.CacheKey
public class CacheKey implements Cloneable, Serializable {
  @Override
  public CacheKey clone() throws CloneNotSupportedException {
    CacheKey clonedCacheKey = (CacheKey) super.clone();
    clonedCacheKey.updateList = new ArrayList<>(updateList);
    return clonedCacheKey;
  }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值