设计模式-原型模式(Prototype)

概述

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

适用场景

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

优点

  • 原型模式在性能上比直接new一个对象性能高
  • 简化创建过程

缺点

  • 必须配备克隆方法
  • 对克隆复杂对象或克隆出的对象进行复杂改造时, 容易引入风险
  • 深克隆, 浅克隆要运用得当

模式角色

  • Prototype : 声明一个克隆自身的接口, 需要注意的是, 在Java中Object类中存在了clone方法, 所以这个角色就相当于Object类的角色了, 使用时不需要再声明接口了, 直接覆盖Object的clone方法即可
  • ConcretePrototype : 实现一个克隆自身的操作
  • Client : 即客户端, 让一个原型克隆自身从而创建一个新的对象

代码实现

  • java中要实现clone, 需要实现Cloneable接口, 这是一个标记接口
  • 重写Object类的clone方法
/**
 * 原型模式
 *
 * @author 七夜雪
 * @create 2018-11-23 10:51
 */
public class Person implements Cloneable {
    private String name;
    private Integer age;
    private String address;
    private String company;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", company='" + company + '\'' +
                ", hashCode='" + hashCode() + '\'' +
                '}';
    }
    // ..............Setter, Getter方法省略.................
 }

测试代码:

    public static void main(String[] args) throws Exception {
        // 原型
        Person prototype = new Person();
        prototype.setName("萧忆情");
        prototype.setAddress("洛阳");
        prototype.setCompany("听雪楼");
        prototype.setAge(18);
        Person clone = (Person)prototype.clone();
        System.out.println("原型:" + prototype);
        System.out.println("拷贝:" + clone);
    }

输出结果:

原型:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', hashCode='356573597'}
拷贝:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', hashCode='1735600054'}
  • 对于都是简单属性的类, 这种操作并没有什么问题, 如果属性中存在复杂对象, 就可能会存在问题, 现在我们在Person类中增加一个Date类型的birthday属性, 然后修改一下测试方法试一下:
    public static void main(String[] args) throws Exception {
        // 原型
        Person prototype = new Person();
        prototype.setName("萧忆情");
        prototype.setAddress("洛阳");
        prototype.setCompany("听雪楼");
        prototype.setAge(18);
        prototype.setBirthday(new Date());
        Person clone = (Person)prototype.clone();
        System.out.println("原型:" + prototype);
        System.out.println("拷贝:" + clone);
        // 这里如果直接调用clone.setBirthday()方法是并没有问题的, 因为prototype和clone是两个不同的对象了,直接调用set方法的话, 只是会把clone对象的Birthday属性指向一个新的Date对象
        clone.getBirthday().setTime(211111212121L);
        System.out.println("--------------更新了clone对象的birthday属性---------------");
        System.out.println("原型:" + prototype);
        System.out.println("拷贝:" + clone);
    }

输出结果:

原型:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', birthday='Fri Nov 23 11:15:11 CST 2018', hashCode='1836019240'}
拷贝:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', birthday='Fri Nov 23 11:15:11 CST 2018', hashCode='325040804'}
--------------更新了clone对象的birthday属性---------------
原型:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', birthday='Thu Sep 09 18:00:12 CST 1976', hashCode='1836019240'}
拷贝:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', birthday='Thu Sep 09 18:00:12 CST 1976', hashCode='325040804'}

从上面的输出结果可以看出, 这种情况下prototype和clone对象的birthday属性还是同一个对象, 这种就是浅克隆, 又叫浅拷贝, 这种情况就需要改写clone方法, 对birthday属性再进行一次clone操作, 修改后的clone方法如下:

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clone = (Person) super.clone();
        clone.birthday = (Date) this.birthday.clone();
        return clone;
    }

修改完之后, 再执行上面的测试用例, 就会发现结果已经正确了:

原型:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', birthday='Fri Nov 23 11:20:51 CST 2018', hashCode='1836019240'}
拷贝:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', birthday='Fri Nov 23 11:20:51 CST 2018', hashCode='325040804'}
--------------更新了clone对象的birthday属性---------------
原型:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', birthday='Fri Nov 23 11:20:51 CST 2018', hashCode='1836019240'}
拷贝:Person{name='萧忆情', age=18, address='洛阳', company='听雪楼', birthday='Thu Sep 09 18:00:12 CST 1976', hashCode='325040804'}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值