原型模式

原型模式是用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。是不是很难理解?其实简单一句话就可以基本上概括它了:本身就是克隆,通过克隆的方式来获取一个新对象。
原型模式有两种克隆方式:浅克隆和深克隆两种
浅克隆

有一个Person类,它有age和name两个属性:

public class Person implements Cloneable {
     private int age;
     private String name;
     public Object clone(){
         Person person = null;
         try {
             //进行克隆
             person = (Person) super.clone();
         } catch (CloneNotSupportedException e) {
             e.printStackTrace();
         }
         return person;
     }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

要点:Person类首先要继承Cloneable接口, 然后重写clone方法。
下面做个测试

public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(10);
        person.setName("ming");
        System.out.println("person  "+person.toString());
        Person person1 = (Person) person.clone();
        System.out.println("clone person   "+person1.toString());
    }
}

结果如下:
person Person{age=10, name=’ming’}
clone person Person{age=10, name=’ming’}
可以看出,浅克隆复制出来了一个一模一样的完整对象。
但是浅克隆有一定的问题,如果在类中的成员变量含有地址引用的变量,比如数组,list,其他类的实例等,这样浅克隆得到的对象的地址引用和原对象是一样,如果原对象的变量发生了更改,克隆得到的变量也会发生变化。这样的问题就得有深克隆来解决了。

深克隆

public class DeepClone implements Cloneable{
    private int age;
    private String name;
    private ArrayList<Integer> list;

    public Object clone(){
        DeepClone deepClone = null;
        try {
            deepClone = (DeepClone) super.clone();
            deepClone.list = (ArrayList<Integer>) this.list.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return deepClone;
    }

    public void setList(ArrayList<Integer> list) {
        this.list = list;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public List<Integer> getList() {
        return list;
    }

    @Override
    public String toString() {
        return "DeepClone{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", list=" + list +
                '}';
    }
}

测试:

public class Test2 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        DeepClone deepClone = new DeepClone();
        deepClone.setAge(10);
        deepClone.setName("ming");
        deepClone.setList(list);
        DeepClone deepClone1 = (DeepClone) deepClone.clone();
        System.out.println(deepClone.toString());
        System.out.println(deepClone1.toString());
        System.out.println("_______________________________");
        //改变其中一个地址引用变量的值
        list.add(3);
        System.out.println(deepClone.toString());
        System.out.println(deepClone1.toString());
    }
}

得到的结果是:
DeepClone{age=10, name=’ming’, list=[1, 2]}
DeepClone{age=10, name=’ming’, list=[1, 2]}


DeepClone{age=10, name=’ming’, list=[1, 2, 3]}
DeepClone{age=10, name=’ming’, list=[1, 2]}

这样就可以看到在深克隆的情况下,如果改变原有地址引用变量的值,并不是影响到新克隆对象的值。两种对象互为独立。

注意: 要使用clone方法,类的成员变量上不要增加final关键字。因为final类型是不允许重赋值的。

优点
(1)原型模式是在内存中二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量对象时,原型模式可能更好的体现其优点。
(2)还有一个重要的用途就是保护性拷贝,也就是对某个对象对外可能是只读的,为了防止外部对这个只读对象的修改,通常可以通过返回一个对象拷贝的形式实现只读的限制。

缺点
1)这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的,在实际开发中应该注意这个潜在问题。优点是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。
(2)通过实现Cloneable接口的原型模式在调用clone函数构造实例时并不一定比通过new操作速度快,只有当通过new构造对象较为耗时或者说成本较高时,通过clone方法才能够获得效率上的提升。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值