java设计模式——原型模式

11 篇文章 0 订阅
3 篇文章 0 订阅

名词解释

Prototype Pattern

是指原型实例指定创建对象的种类,并且通过拷贝这些原型的属性和值来创建新的对象。

应用场景

  1. 类初始化消耗资源较多。
  2. new 产生的一个对象需要非常繁琐的过程(比如数据准备、访问权限等)
  3. 构造函数比较复杂。
  4. 循环体中生产大量对象时。

写法

简单写法

常规的简单写法是先定义一个接口

public interface Prototype{
    Prototype clone();
}

然后让需要克隆的类实现这个接口,并在 clone 方法中实现对象的创建和给属性赋值,比如:

public class ConcretePrototype implements Prototype {

    String attributeA;
    List<String> attributeC;
    @Override
    public Prototype clone() {
        ConcretePrototype cloneObj = new ConcretePrototype();
        cloneObj.attributeA = this.attributeA;
        cloneObj.attributeC = this.attributeC;
        return cloneObj;
    }

    public String getAttributeA() {
        return attributeA;
    }

    public void setAttributeA(String attributeA) {
        this.attributeA = attributeA;
    }
    
    public List<String> getAttributeC() {
        return attributeC;
    }

    public void setAttributeC(List<String> attributeC) {
        this.attributeC = attributeC;
    }
}

存在的问题

在上面实现类的代码中

List<String> attributeC;
...
cloneObj.attributeC = this.attributeC;

当对引用数据类型进行赋值时,不能直接用 = 来赋值,这样会使得被克隆出来的对象和原对象中该属性对应用到同一个地址,修改其中一个的值,另一个的只也修改了,解决办法是改用深克隆

深克隆

只通过实现 Cloneable 接口

如果存在自定义的引用数据类型,则在每一个引用的类上也要实现 Cloneable 接口,且每一次调用 clone 方法时都要注意检查对引用类型的深克隆处理

比如:Wheel类

public class Wheel implements Cloneable {
    private int size ;
    public Wheel(int size) {
        this.size = size;
    }
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Car类会调用 Wheel类

public class Car implements Cloneable{
   private String name ;
   private Wheel wheel ;
    public Car(String name, Wheel wheel) {
        this.name = name;
        this.wheel = wheel;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Wheel getWheel() {
        return wheel;
    
    public void setWheel(Wheel wheel) {
        this.wheel = wheel;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Car c = (Car)super.clone();
        c.setWheel((Wheel)c.getWheel().clone()); //重点是这里,调用依赖类的地方也要进行克隆处理
        return c;
    }
}

只通过实现 Serializable 接口

同样,如果存在自定义的引用数据类型,则在每一个引用的类上也要实现 Serializable 接口,不同的是,被引用的类不用单独处理 clone 方法,只需要在最终调用的类那里通过 反序列化 来实现深克隆就可以

代码如下:Wheel2

public class Wheel2 implements Serializable {
    private int size ;
    public Wheel2(int size) {
        this.size = size;
    }
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
}

Car2 类来调用 Wheel2

public class Car2 implements Serializable {
   private String name ;
   private Wheel2 wheel2 ;
    public Car2(String name, Wheel2 wheel2) {
        this.name = name;
        this.wheel2 = wheel2;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Wheel2 getWheel2() {
        return wheel2;
    }
    public void setWheel2(Wheel2 wheel2) {
        this.wheel2 = wheel2;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        try{
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);

            Car2 copy = (Car2)ois.readObject();
            return copy;

        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}

同时实现Cloneable ,Serializable 接口

让需要克隆的类实现 Cloneable 接口和Serializable接口,

代码如下,注意clone方法的实现

public class DeepClonePrototype implements Prototype,Cloneable, Serializable {

    String attributeA;
    List<String> attributeC;
    @Override
    public Prototype clone() {
        try{
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);

            DeepClonePrototype copy = (DeepClonePrototype)ois.readObject();
            return copy;

        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    public String getAttributeA() {
        return attributeA;
    }

    public void setAttributeA(String attributeA) {
        this.attributeA = attributeA;
    }

    public List<String> getAttributeC() {
        return attributeC;
    }

    public void setAttributeC(List<String> attributeC) {
        this.attributeC = attributeC;
    }

}
知识点

因为 List 类的实现类,如 ArrayList 也是实现了CloneableSerializable接口的,所以其他类来可以对包含 List 的实例的对象进行深克隆

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

存在的问题

会对单例造成破坏,不过解决起来很简单,以下的任意一种思路都是可行的

  • 单例类不实现 Cloneable 接口
  • 在单例类中重写clone()方法,在clone 方法中返回单例对象

代码很简单,就不贴了。

Spring中的应用

spring 中的 scope =“prototype” 和 scope =“singleton” 用来表示对象创建的方式, prototype 表示通过已有对象来进行克隆,具体表现为每一个线程或者请求都会单独创建一次对象,以保证线程间数据完全隔离, singleton表示只创建单例,各线程得到的是同一个实例,这有利于数据共享。

所以,到底是配置prototype 还是 singleton 要看具体场景

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值