JAVA设计模式——原型模式

原型模式是一种创建型设计模式。原型模式的思想是:通过对原型对象的克隆来获得新对象

原型模式涉及3个角色:

  • 抽象原型(Prototype):具体原型的抽象。如果是抽象类,则实现Cloneable接口并重写clone()方法;如果是接口,则只给出规范,由实现Cloneable接口并重写clone()方法。
  • 具体原型(Concrete Prototype):客户实际所需要的对象的类型。
  • 客户(Client):提出创建对象的请求。

结构图:
这里写图片描述

代码实现:

抽象原型:

public abstract class Prototype implements Cloneable {
    // 声明一些属性用作演示
    protected int demoInt;
    protected String demoString;
    protected ArrayList<String> demoList;

    // 浅克隆
    public Prototype clone() {
        Prototype cloneObj = null;
        try {
            cloneObj = (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return cloneObj;
    }

    // 深克隆
    @SuppressWarnings("unchecked")
    public Prototype deepClone() {
        Prototype cloneObj = null;
        try {
            cloneObj = (Prototype) super.clone();
            cloneObj.setDemoList((ArrayList<String>) this.getDemoList().clone());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return cloneObj;
    }

    // Getters and Setters
    // ......
}

具体原型:

public class ConcretePrototype extends Prototype {
    public ConcretePrototype(){
        this.demoInt = 111;
        this.demoString = "AAA";
        this.demoList = new ArrayList<>(2);
        demoList.add("aaa111");
        demoList.add("111aaa");
    }
}

客户:

public class Client {
    private Prototype prototype = new ConcretePrototype();

    public Prototype getPrototype() {
        return prototype.clone();
    }

    public Prototype getDeepPrototype() {
        return prototype.deepClone();
    }

    // 测试
    public static void main(String[] args) {
        Client client = new Client();
        Prototype a = client.getPrototype();
        System.out.printf("%s, %s, %s\n", a.getDemoInt(), a.getDemoString(), a.getDemoList());
        Prototype b = client.getDeepPrototype();
        System.out.printf("%s, %s, %s\n", b.getDemoInt(), b.getDemoString(), b.getDemoList());

        // 改变原型对象的内容看看效果
        client.prototype.getDemoList().remove(0);
        client.prototype.setDemoString("TEST");
        System.out.printf("%s, %s, %s\n", a.getDemoInt(), a.getDemoString(), a.getDemoList());
        System.out.printf("%s, %s, %s\n", b.getDemoInt(), b.getDemoString(), b.getDemoList());
    }
}

运行结果:

111, AAA, [aaa111, 111aaa]
111, AAA, [aaa111, 111aaa]
111, AAA, [111aaa]
111, AAA, [aaa111, 111aaa]

java.lang.Object类的clone()方法实现的是浅克隆,除了基本数据类型和java.lang.String类型的数据是值复制外,其余所有引用类型只复制一个引用,这个引用与被复制的对象的属性引用指向同一个对象。要实现深克隆,则必须人为指定对这些对象进行复制,前提是这些对象的类型实现了Cloneable接口。当然,深克隆也可以通过序列化/反序列化的方法来实现,这种方式使得深克隆变得非常简单,但也需要注意一些细节问题,这里不展开。

上面的测试例子可以看到,a是浅克隆得到的对象,因此当原型对象引用类型的属性demoList发生改变时,a对象的demoList也跟着改变;而b是深克隆得到的对象,b对象的引用类型属性demoList指向的则是新的List对象,所以原型对象改变,b并没有跟着改变。

由于绕过了构造器,原型模式能一定程度提高性能,尤其是当新建对象的开销比较大时。但其缺点也是明显的,在实现克隆方法时,需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,尤其当这个类引用不支持实例化的间接对象,或者可能会出现循环引用情况的时候。

原型模式很少单独使用,更多的时候是和其它设计模式一起出现。另外,这里提供一个可以使用原型设计模式的场景:缓存。缓存中的对象就相当于原型对象,当我们从缓存中取对象时,实际上取得的是这个对象的克隆。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值