设计模式-原型模式

点击这里查看更多设计模式

 

基本概念

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

应用场景举例

1. 创建一个对象成本较高时可考虑选用原型模式,如一个对象比比较复杂,创建过程耗时较长,或者占用CPU较高等;

2. 当程序中需要使用一个对象的大部分信息,而只对部分信息做出修改时,可使用原型模式。

实现

在Java中,原型对象实现Cloneable接口,实现实现clone方法即可实现克隆,但要注意浅克隆与深克隆的区别。

浅克隆

如果原型对象的成员变量是值类型(String、int、double等),调用clone方法之后将值类型的成员变量复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,即克隆对象和原型对象成员变量的引用地址相同。

 

public class Company implements Cloneable {
    private String id;
    private String name;
    private Department department;

    public Company(String id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public String getInfo() {
        return "{" + id + ", " + name + "}";
    }

    public Department getDepartment() {
        return department;
    }

    @Override
    protected Company clone() throws CloneNotSupportedException {
        // 克隆对象
        return (Company) super.clone();
    }
}

public class Department {
    private String id;
    private String name;

    public String getInfo() {
        return "{" + id + ", " + name + "}";
    }

    public Department(String id, String name) {
        this.id = id;
        this.name = name;
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 原型对象
        Company company1 = new Company("A", "公司A", new Department("DA", "部门A"));
        // 打印原型对象的内存地址和值属性
        System.out.println(company1 + ", " + company1.getInfo());
        // 打印原型对象引用成员变量的内存地址和属性
        System.out.println(company1.getDepartment() + ", " + company1.getDepartment().getInfo());
        // 克隆对象
        Company company2 = company1.clone();
        // 打印克隆对象的内存地址和值属性
        System.out.println(company2 + ", " + company2.getInfo());
        // 打印克隆对象引用成员变量的内存地址和属性
        System.out.println(company2.getDepartment() + ", " + company2.getDepartment().getInfo());
    }
}

上述例子中,company1为原型对象,company2为克隆对象,原型对象和克隆对象中的id和name(值类型)一样,说明值类型被复制了一份给company2,但company1和company2的内存地址不同,所以company1和company2不是同一个对象。company1中的引用对象department和company2中的引用对象department的内存地址一样,说明在克隆时,引用类型只复制引用对象的地址。打印结果如下:

如果想要原型对象中的引用对象也被作为原型对象完全克隆一份,就要使用深克隆。

深克隆

方法1:引用对象也实现Cloneable接,在原型对象clone方法中调用引用对象的clone方法,即可实现深克隆。

public class Company implements Cloneable {
    private String id;
    private String name;
    private Department department;

    public Company(String id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public String getInfo() {
        return "{" + id + ", " + name + "}";
    }

    public Department getDepartment() {
        return department;
    }

    @Override
    protected Company clone() throws CloneNotSupportedException {
        Company company = (Company) super.clone();
        // 克隆引用对象
        company.department = company.department.clone();
        return company;
    }
}


public class Department implements Cloneable {
    private String id;
    private String name;

    public String getInfo() {
        return "{" + id + ", " + name + "}";
    }

    public Department(String id, String name) {
        this.id = id;
        this.name = name;
    }

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

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 原型对象
        Company company1 = new Company("A", "公司A", new Department("DA", "部门A"));
        // 打印原型对象的内存地址和值属性
        System.out.println(company1 + ", " + company1.getInfo());
        // 打印原型对象引用成员变量的内存地址和属性
        System.out.println(company1.getDepartment() + ", " + company1.getDepartment().getInfo());
        // 克隆对象
        Company company2 = company1.clone();
        // 打印克隆对象的内存地址和值属性
        System.out.println(company2 + ", " + company2.getInfo());
        // 打印克隆对象引用成员变量的内存地址和属性
        System.out.println(company2.getDepartment() + ", " + company2.getDepartment().getInfo());
    }
}

 

Company的引用类型成员变量Department也实现了Cloneable接口,在Company的clone方法中调用了Cloneable的clone方法进行克隆,因此在克隆Company时Department也会被作为原型对象复制一份。打印结果如下:

方法2:原型对象和引用类型的成员变量都实现实现Serializable接口,在克隆方法中,将对象写入字节流,然后再读取出来即可。

public class Company implements Serializable {
    private String id;
    private String name;
    private Department department;

    public Company(String id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public String getInfo() {
        return "{" + id + ", " + name + "}";
    }

    public Department getDepartment() {
        return department;
    }

    // 深克隆方法
    protected Company deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
        //将对象写入流中,相当于复制一份,原对象还存在于内存中(jvm机制)
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(this);

        //将对象从流中取出
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        return (Company) objectInputStream.readObject();
    }
}

public class Department implements Serializable {
    private String id;
    private String name;

    public String getInfo() {
        return "{" + id + ", " + name + "}";
    }

    public Department(String id, String name) {
        this.id = id;
        this.name = name;
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        // 原型对象
        Company company1 = new Company("A", "公司A", new Department("DA", "部门A"));
        // 打印原型对象的内存地址和值属性
        System.out.println(company1 + ", " + company1.getInfo());
        // 打印原型对象引用成员变量的内存地址和属性
        System.out.println(company1.getDepartment() + ", " + company1.getDepartment().getInfo());
        // 克隆对象
        Company company2 = company1.deepClone();
        // 打印克隆对象的内存地址和值属性
        System.out.println(company2 + ", " + company2.getInfo());
        // 打印克隆对象引用成员变量的内存地址和属性
        System.out.println(company2.getDepartment() + ", " + company2.getDepartment().getInfo());
    }
}

打印结果如下:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值