原型模式

  1. 定义 原型模式就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
  2. 本质 克隆生成对象
  3. 实例 以下已用户的原型来做学习。所谓原型模式,就是java中的克隆技术,以某个对象为原型。复制出新的对象。显然新的对象具备原型对象的特点。效率高(避免了重新执行构造过程步骤)克隆类似于new,但和new不同。new创建新的对象属性采用的是默认值。克隆出来的对象的属性值完全和原型对象相同。并且克隆出的新对象不会影响原型对象,克隆后。还可以再修改克隆对象的值。要实现原型模式,必须实现Cloneable接口,而这个接口里面是空的。 我们也可以想尝试自己实现对象的克隆。

UserPrototype

public class UserPrototype {
    private  String name;
    private  int age;
    private Date birthday;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public UserPrototype clonePrototype(){
        UserPrototype prototype = new UserPrototype();
        prototype.setName(this.name);
        prototype.setAge(this.age);
        prototype.setBirthday(this.birthday);
        return prototype;
    }

clonePrototype() 方法为自己实现的克隆!

调用

 public void testClone(){
        UserPrototype prototype = new UserPrototype();
        prototype.setName("张三");
        prototype.setAge(25);
        prototype.setBirthday(new Date(1520583326));

        UserPrototype prototype1 = prototype.clonePrototype();
        //System.out.println(prototype == prototype1);

        System.out.println("原:"+prototype.getBirthday());
        System.out.println("克隆后:"+prototype1.getBirthday());

        //修改
        prototype.setBirthday(new Date(1530584089));
        prototype.setName("李四");
        prototype.setAge(26);

        System.out.println("修改后原  名称:"+prototype.getName()+"  年龄:"+prototype.getAge()+" 生日:"+prototype.getBirthday());
        System.out.println("修改后克隆 名称:"+prototype1.getName()+"  年龄:"+prototype1.getAge()+" 生日:"+prototype1.getBirthday());

    }

下面在用 java自带的接口来克隆
Phone

public class Phone {
    public String name;
    public String ys;

    public Phone(String name, String ys) {
        this.name = name;
        this.ys = ys;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getYs() {
        return ys;
    }

    public void setYs(String ys) {
        this.ys = ys;
    }

    @Override
    public String toString() {
        return "Phone{" +
                "                            name:'" + name + '\'' +
                ",                             ys:'" + ys + '\'' +
                '}';
    }
}

UserPrototypeCloneable

public class UserPrototypeCloneable implements Cloneable {
    public  String name;
    public  int age;
    public Date birthday;
    public Phone phone;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Phone getPhone() {
        return phone;
    }

    public void setPhone(Phone phone) {
        this.phone = phone;
    }

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

调用

   public void testCloneCloneable() throws CloneNotSupportedException {
        UserPrototypeCloneable prototype = new UserPrototypeCloneable();
        prototype.setName("张三");
        prototype.setAge(25);
        prototype.setBirthday(new Date(1520583326));
        prototype.setPhone(new Phone("IPHONE","RED"));
        UserPrototypeCloneable prototype1 = (UserPrototypeCloneable)prototype.clone();
        //System.out.println(prototype == prototype1);

        System.out.println("原:"+prototype.getBirthday());
        System.out.println("克隆后:"+prototype1.getBirthday());

        System.out.println("修改前UserPrototypeCloneable对象:"+(prototype==prototype1));
        System.out.println("修改前生日对象对象:"+(prototype.getBirthday()==prototype1.getBirthday()));
        System.out.println("修改前Phone对象对象:"+(prototype.getPhone()==prototype1.getPhone()));

        //修改
        prototype1.getBirthday().setDate(1530584089);
        prototype1.getPhone().setName("HUA WEI");


        System.out.println("修改后原  名称:"+prototype.getName()+"  年龄:"+prototype.getAge()+" 生日:"+prototype.getBirthday()+" 手机:"+prototype.getPhone());
        System.out.println("修改后克隆 名称:"+prototype1.getName()+"  年龄:"+prototype1.getAge()+" 生日:"+prototype1.getBirthday()+" 手机:"+prototype1.getPhone());
        System.out.println("修改后生日对象对象:"+(prototype.getBirthday()==prototype1.getBirthday()));
    }

输出

原:Sun Jan 18 22:23:03 CST 1970
克隆后:Sun Jan 18 22:23:03 CST 1970
修改前UserPrototypeCloneable对象:false
修改前生日对象对象:true
修改前Phone对象对象:true
修改后原  名称:张三  年龄:25 生日:Tue Nov 25 22:23:03 CST 4192566 手机:Phone{                            name:'HUA WEI',                             ys:'RED'}
修改后克隆 名称:张三  年龄:25 生日:Tue Nov 25 22:23:03 CST 4192566 手机:Phone{                            name:'HUA WEI',                             ys:'RED'}
修改后生日对象对象:true

发现克隆后 prototype和prototype1 不是同一个对象,但是日期对象和Phone克隆前和克隆后是同一个对象。这样就不科学了,克隆后日期和Phone和原来的对象不一样才对呀!我们重新修改了克隆后的值发现日期对象修改后又会影响克隆前的对象。这样就不对了!由此可见JDK的克隆对应用类型的克隆是自己拷贝其引用地址,这样不科学!这个其实也就是浅克隆。


如何才能保证引用对象克隆后不是同一个对象呢!这样就引入了深度克隆!下面演示深度克隆!

修改PHONE类

public class Phone implements Serializable ,Cloneable{
    private static final long serialVersionUID = -8637667978831245045L;
    public String name;
    public String ys;

    public Phone(String name, String ys) {
        this.name = name;
        this.ys = ys;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getYs() {
        return ys;
    }

    public void setYs(String ys) {
        this.ys = ys;
    }

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

    @Override
    public String toString() {
        return "Phone{" +
                "                            name:'" + name + '\'' +
                ",                             ys:'" + ys + '\'' +
                '}';
    }
    }

UserPrototypeCloneableDeep

public class UserPrototypeCloneableDeep  implements Cloneable ,Serializable{
    private static final long serialVersionUID = -3209761451599706716L;
    public  String name;
    public  int age;
    public Date birthday;
    public Phone phone;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Phone getPhone() {
        return phone;
    }

    public void setPhone(Phone phone) {
        this.phone = phone;
    }

    @Override
    public Object clone() {

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            UserPrototypeCloneableDeep  userPrototypeCloneableDeep= (UserPrototypeCloneableDeep)ois.readObject();
            userPrototypeCloneableDeep.setBirthday((Date) userPrototypeCloneableDeep.getBirthday().clone());
            userPrototypeCloneableDeep.setPhone((Phone) userPrototypeCloneableDeep.getPhone().clone());
            return userPrototypeCloneableDeep;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

测试

 @Test
    public void testCloneCloneableDeep() {
        UserPrototypeCloneableDeep prototype = new UserPrototypeCloneableDeep();
        prototype.setName("张三");
        prototype.setAge(25);
        prototype.setBirthday(new Date(1520583326));
        prototype.setPhone(new Phone("IPHONE","RED"));
        UserPrototypeCloneableDeep prototype1 = (UserPrototypeCloneableDeep)prototype.clone();
        //System.out.println(prototype == prototype1);

        System.out.println("原:"+prototype.getBirthday());
        System.out.println("克隆后:"+prototype1.getBirthday());

        System.out.println("修改前UserPrototypeCloneable对象:"+(prototype==prototype1));
        System.out.println("修改前生日对象对象:"+(prototype.getBirthday()==prototype1.getBirthday()));
        System.out.println("修改前Phone对象对象:"+(prototype.getPhone()==prototype1.getPhone()));

        //修改
        prototype1.getBirthday().setDate(1530584089);
        prototype1.getPhone().setName("HUA WEI");

        System.out.println("修改后原  名称:"+prototype.getName()+"  年龄:"+prototype.getAge()+" 生日:"+prototype.getBirthday()+" 手机:"+prototype.getPhone());
        System.out.println("修改后克隆 名称:"+prototype1.getName()+"  年龄:"+prototype1.getAge()+" 生日:"+prototype1.getBirthday()+" 手机:"+prototype1.getPhone());
        System.out.println("修改后生日对象对象:"+(prototype.getBirthday()==prototype1.getBirthday()));
    }

输出

原:Sun Jan 18 22:23:03 CST 1970
克隆后:Sun Jan 18 22:23:03 CST 1970
修改前UserPrototypeCloneable对象:false
修改前生日对象对象:false
修改前Phone对象对象:false
修改后原  名称:张三  年龄:25 生日:Sun Jan 18 22:23:03 CST 1970 手机:Phone{                            name:'IPHONE',                             ys:'RED'}
修改后克隆 名称:张三  年龄:25 生日:Tue Nov 25 22:23:03 CST 4192566 手机:Phone{                            name:'HUA WEI',                             ys:'RED'}
修改后生日对象对象:false

例子地址

posted on 2018-03-11 22:22  未亦末  阅读(122)  评论(0编辑  收藏  举报