2

设计模式学习(五):原型模式 - Grey Zeng

 1 year ago
source link: https://www.cnblogs.com/greyzeng/p/16869568.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

设计模式学习(五):原型模式

作者:Grey

原文地址:

博客园:设计模式学习(五):原型模式

CSDN:设计模式学习(五):原型模式

原型模式#

原型模式是创建型模式。

如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段的值都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式。

实际上,创建对象包含的申请内存、给成员变量赋值这一过程,本身并不会花费太多时间,或者说对于大部分业务系统来说,这点时间完全是可以忽略的。应用一个复杂的模式,只得到一点点的性能提升,这就是所谓的过度设计,得不偿失。但是,如果对象中的数据需要经过复杂的计算才能得到(比如排序、计算哈希值),或者需要从 RPC 、网络、数据库、文件系统等非常慢速的 I/O 中读取,每次读取一次的代价都很高,在这种情况下,我们就可以利用原型模式,从其他已有对象中直接拷贝得到,而不用每次在创建新对象的时候,都重复执行这些耗时的操作。

原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,典型的应用是对象的克隆方法,示例代码如下

public class Person implements Cloneable {
    String name = "lisa";
    int age = 1;
    Location loc = new Location("xy", 10);

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person p = (Person) super.clone();
        p.loc = (Location) loc.clone();
        return p;
    }

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + ", loc=" + loc + '}';
    }
}
public class Location implements Cloneable {
    private String street;
    private int roomNo;

    public Location(String street, int roomNo) {
        this.street = street;
        this.roomNo = roomNo;
    }

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

    @Override
    public String toString() {
        return "Location{" + "street='" + street + '\'' + ", roomNo=" + roomNo + '}';
    }
}
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p = new Person();
        System.out.println(p);
        Person p2 = (Person) p.clone();
        System.out.println(p2);
    }
}

本示例的 UML 图如下:

image

注:Java 自带的 clone() 方法进行的就是浅克隆。而如果我们想进行深克隆,可以直接在类中调用父类的克隆方法,即: super.clone() 后,手动给克隆对象的相关属性分配另一块内存,不过如果当原型对象维护很多引用属性的时候,手动分配会比较烦琐。因此,在 Java 中,如果想完成原型对象的深克隆,则通常使用序列化的方式。

例如:克隆一个巨大的 HashMap,如果构建该 HashMap 的代价很大,我们可以通过

方式一:先调用 HashMap 默认的克隆方法,然后递归拷贝 HashMap 里面的内容,直到类型是基础类型为止;

方式二:使用序列化方式克隆。

关于序列化克隆的示例代码如下

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class DeepCloneDemo {
    public static void main(String[] args) {
        List<String> hobbies = new ArrayList<>();
        hobbies.add("唱歌");
        hobbies.add("跳舞");
        Prototype p = new Prototype();
        p.setAge(18);
        p.setName("zhangsan");
        p.setHobbits(hobbies);
        Prototype clone = p.clone();
        System.out.println(clone.getAge());
        System.out.println(clone.getName());
        System.out.println(clone.getHobbits());
    }
}

// 待克隆对象
class Prototype implements Cloneable, Serializable {
    private int age;
    private String name;
    private List<String> hobbits;

    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<String> getHobbits() {
        return hobbits;
    }

    public void setHobbits(List<String> hobbits) {
        this.hobbits = hobbits;
    }

    @Override
    protected Prototype clone() {
        return deepClone();
    }

    public Prototype deepClone() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (Prototype) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

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

如果只是增量拷贝,可以通过浅拷贝拿到一个新的 HashMap ,然后拿到增量的数据单独进行深拷贝即可。

更多地,Spring 中创建对象的方式默认采用单例模式,可以通过设置 @Scope("prototype") 注解将其改为原型模式。

UML 和 代码#

UML 图

代码

更多#

设计模式学习专栏

参考资料#


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK