前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式---原型模式

设计模式---原型模式

作者头像
技术文章精选
发布2022-11-08 16:40:06
1770
发布2022-11-08 16:40:06
举报
文章被收录于专栏:优质文章优质文章

简述

  • 类型:创建型
  • 目的:通过拷贝快速创建相同或相似对象。

接下来我们看一个需要改进的案例。

优化案例

话不多说,先来看一个创建相同或相似对象的传统写法。

最初版v0

代码语言:javascript
复制
public class Department {    private String name;    private String country;    private String province;    private String city;    private List<Employee> employees;     public String getName() {        return name;    }     public String getCountry() {        return country;    }     public String getProvince() {        return province;    }     public String getCity() {        return city;    }     public List<Employee> getEmployees() {        return employees;    }     public Department(String name, String country, String province,                      String city, List<Employee> employees) {        this.name = name;        this.country = country;        this.province = province;        this.city = city;        this.employees = employees;    }} public class Employee {    private String name;    private String sex;    private int age;    private String country;    private String province;    private String city;    private String post;     public String getName() {        return name;    }     public String getSex() {        return sex;    }     public int getAge() {        return age;    }     public String getCountry() {        return country;    }     public String getProvince() {        return province;    }     public String getCity() {        return city;    }     public String getPost() {        return post;    }     public Employee(String name, String sex, int age,                    String country, String province,                    String city, String post) {        this.name = name;        this.sex = sex;        this.age = age;        this.country = country;        this.province = province;        this.city = city;        this.post = post;    }}

已知一个Department类型的对象,我们想构造一个相似的对象。

代码语言:javascript
复制
public class Client {    public static void main(String[] args) {        Employee emp = new Employee("张三", "男", 15, "中国", "江西省", "南昌市", "124-1241-1353");        Department department = new Department("开发部", "中国", "江西省", "南昌市", List.of(e)); // 已知对象        Department department1 = new Department(department.getName(), department.getCountry(), department.getProvince(), department.getCity(), department.getPost()); // 拷贝对象    }}

可以感受到,对象拷贝的朴素写法非常的麻烦。而且想到每一处对象拷贝都需要这样写就感觉头皮发麻。

为了解决这个问题,我们引入原型模式。请看以下样例。

修改版v1(浅拷贝)

代码语言:javascript
复制
public class Department {    private String name;    private String country;    private String province;    private String city;    private List<Employee> employees;     public Department(String name, String country, String province,                      String city, List<Employee> employees) {        this.name = name;        this.country = country;        this.province = province;        this.city = city;        this.employees = employees;    }} public class Employee {    private String name;    private String sex;    private int age;    private String country;    private String province;    private String city;    private String post;     public Employee(String name, String sex, int age,                    String country, String province,                    String city, String post) {        this.name = name;        this.sex = sex;        this.age = age;        this.country = country;        this.province = province;        this.city = city;        this.post = post;    }}

使用clone()方法拷贝目标对象。

代码语言:javascript
复制
public class Client {    public static void main(String[] args) throws CloneNotSupportedException {        Employee e = new Employee("张三", "男", 15, "中国", "江西省", "南昌市", "124-1241-1353");        Department department = new Department("开发部", "中国", "江西省", "南昌市", List.of(e));        Department department1 = (Department)department.clone();        System.out.println(department == department1); // false        System.out.println(department.employees == department1.employees); // true    }}

我们发现第8行输出true,这说明两个对象的employees的引用相同,这会导致修改其中一个employees的元素会影响到另一个,这并不好。

如何解决属性相同引用的问题?看以下样例。

修改版v2(深拷贝)

代码语言:javascript
复制
public class Department implements Cloneable {    private String name;    private String country;    private String province;    private String city;    private List<Employee> employees;     public Department(String name, String country, String province,                      String city, List<Employee> employees) {        this.name = name;        this.country = country;        this.province = province;        this.city = city;        this.employees = employees;    }     @Override    public Object clone() throws CloneNotSupportedException {        Department department = (Department)super.clone();        List<Employee> emps = new ArrayList<>();        for (int i = 0; i < department.employees.size(); i ++) {            emps.add((Employee) employees.get(i).clone());        }        department.employees = emps;        return department;    }} public class Employee implements Cloneable {    private String name;    private String sex;    private int age;    private String country;    private String province;    private String city;    private String post;     public Employee(String name, String sex, int age,                    String country, String province,                    String city, String post) {        this.name = name;        this.sex = sex;        this.age = age;        this.country = country;        this.province = province;        this.city = city;        this.post = post;    }     @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }}

使用clone() 拷贝对象,因为类以及类中的属性也重写了clone()

代码语言:javascript
复制
public class Client {    public static void main(String[] args) throws CloneNotSupportedException {        Employee e = new Employee("张三", "男", 15, "中国", "江西省", "南昌市", "124-1241-1353");        Department department = new Department("开发部", "中国", "江西省", "南昌市", List.of(e));        Department department1 = (Department)department.clone();        System.out.println(department == department1); // false        System.out.println(department.employees == department1.employees); // false    }}

虽然这种方式可以深拷贝,但是这会让代码量激增。

序列化与反序列化可以解决这个问题。

修改版v3(序列化与反序列化)(推荐使用)

代码语言:javascript
复制
public class Department {    private String name;    private String country;    private String province;    private String city;    private List<Employee> employees;     public Department(String name, String country, String province,                      String city, List<Employee> employees) {        this.name = name;        this.country = country;        this.province = province;        this.city = city;        this.employees = employees;    }} public class Employee {    private String name;    private String sex;    private int age;    private String country;    private String province;    private String city;    private String post;     public Employee(String name, String sex, int age,                    String country, String province,                    String city, String post) {        this.name = name;        this.sex = sex;        this.age = age;        this.country = country;        this.province = province;        this.city = city;        this.post = post;    }}

序列化与反序列化的实现方式有很多种,本文使用Gson来实现。以下是样例。

代码语言:javascript
复制
public Client {    public static void main(String[] args) throws CloneNotSupportedException {        Employee e = new Employee("张三", "男", 15, "中国", "江西省", "南昌市", "124-1241-1353");        Department department = new Department("开发部", "中国", "江西省", "南昌市", List.of(e));        Gson gson = new Gson();        String s = gson.toJson(department);        Department department1 = s.fromJson(s, Department.class);        System.out.println(department == department1); // false        System.out.println(department.employees == department1.employees); // false    }}

基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。

总结

优点

  • 由于是直接从内存中读取对象进行克隆,所以性能卓越。
  • 代码量不论是相较于传统写法要精简很多,尤其是序列化与反序列化的方式。

缺点

  • 代码的理解难度增加。尤其是深拷贝的理解较为复杂。

适用场景

  • 适用于只有细微参数变动的对象创建。
  • 适用于需要备份的场景。如,当业务执行过程中,某种情况下需要数据回滚的时候,提前备份可以使用。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 简述
  • 优化案例
    • 最初版v0
      • 修改版v1(浅拷贝)
        • 修改版v2(深拷贝)
          • 修改版v3(序列化与反序列化)(推荐使用)
          • 总结
            • 优点
              • 缺点
                • 适用场景
                相关产品与服务
                文件存储
                文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档