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

设计模式,学习,原型,模式 · 浏览次数 : 365

小编点评

**原型模式学习(五):原型模式作者:Grey原文地址:博客园:设计模式学习(五):原型模式CSDN:设计模式学习(五):原型模式原型模式原型模式是创建型模式。 **原型模式简介** 原型模式是一种创建对象的模式,它通过对已有对象进行复制的方式创建新的对象来降低创建对象的成本。这种模式通常用于创建对象时,对象的数据结构相同,但对象的类型不同。 **原型模式的优点** * **节省创建对象的成本:**创建对象的成本通常比使用反射或动态代理要更高。 * **创建对象时可重用原型:**通过复制原型,我们可以创建多个新对象,每个对象都指向相同的原型对象。 * **改善性能:**通过减少创建对象的次数,原型模式可以显著提高应用程序的性能。 **原型模式的缺点** * **原型对象可能存在内存泄漏问题:**当原型对象不再使用时,其资源可能无法释放,导致内存泄漏。 * **原型模式的创建过程可能比较复杂:**创建原型对象需要手动设置其属性值,这可能在某些情况下比较困难。 **原型模式的应用场景** * 创建具有相同数据结构的多个对象。 * 创建需要从多个源对象中获取数据的对象。 * 创建需要进行性能测试的对象。 **原型模式的示例** ```java public class Person implements Cloneable { private String name; private int age; private Location loc; @Override protected Object clone() throws CloneNotSupportedException { Person p = (Person) super.clone(); p.loc = (Location) loc.clone(); return p; } // 其他方法省略... } ``` **结论** 原型模式是一种创建对象的新模式,它可以有效地降低创建对象的成本,并通过创建对象时可重用原型,改善应用程序的性能。但是,原型模式也有一些缺点,例如可能存在内存泄漏问题,创建原型对象可能比较复杂。

正文

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

作者: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 图

代码

更多

设计模式学习专栏

参考资料

与设计模式学习(五):原型模式相似的内容:

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

设计模式学习(五):原型模式 作者:Grey 原文地址: 博客园:设计模式学习(五):原型模式 CSDN:设计模式学习(五):原型模式 原型模式 原型模式是创建型模式。 如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段的值都相同),在这种情况下,我们可以利用对已有对象(原型)进

设计模式学习(三):工厂模式

设计模式学习(三):工厂模式 作者:Grey 原文地址: 博客园:设计模式学习(三):工厂模式 CSDN:设计模式学习(三):工厂模式 工厂模式 工厂模式是创建型模式,工厂模式分为:简单工厂,工厂方法和抽象工厂三种类型。 简单工厂 这个模式很简单,比如我们需要制造不同类型的鼠标,我们只需要创建一个鼠

设计模式学习(六):代理模式

设计模式学习(六):代理模式 作者:Grey 原文地址: 博客园:设计模式学习(六):代理模式 CSDN:设计模式学习(六):代理模式 代理模式 代理模式是结构型模式,分为静态代理和动态代理。 静态代理 举个例子,假设需要在某个类的某段代码的前后加上日志记录,就可以通过静态代理的方式实现,代码如下

设计模式学习(七):适配器模式

设计模式学习(七):适配器模式 作者:Grey 原文地址: 博客园:设计模式学习(七):适配器模式 CSDN:设计模式学习(七):适配器模式 适配器模式 适配器模式是一种结构型模式。 举例说明,假设有一个播放器,需要根据不同格式以及对应的文件来播放,接口设计如下: public interface

设计模式学习(八):桥接模式

设计模式学习(八):桥接模式 作者:Grey 原文地址: 博客园:设计模式学习(八):桥接模式 CSDN:设计模式学习(八):桥接模式 桥接模式 桥接模式是一种结构型模式。它将抽象部分和实现部分分离,使他们可以独立地变化。 使用桥接模式,可以将抽象和具体的发展单独分支(即:抽象中持有一个具体的引用)

设计模式学习(十):门面模式

设计模式学习(十):门面模式 作者:Grey 原文地址: 博客园:设计模式学习(十):门面模式 CSDN:设计模式学习(十):门面模式 门面模式 门面模式是一种结构型模式。 门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。 假设建造一个房子需要有如下三个步骤: 第一步,和泥 第二

设计模式学习(十一):组合模式

设计模式学习(十一):组合模式 作者:Grey 原文地址: 博客园:设计模式学习(十一):组合模式 CSDN:设计模式学习(十一):组合模式 组合模式 组合模式是一种结构型模式。 组合模式中,最常用的一个用法就是目录层级的遍历,话不多说,直接上代码,主方法中 public class Main {

设计模式学习(十三):观察者模式

设计模式学习(十三):观察者模式 作者:Grey 原文地址: 博客园:设计模式学习(十三):观察者模式 CSDN:设计模式学习(十三):观察者模式 观察者模式 观察者模式是一种行为型模式。在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。 一般可以用做事件处理

设计模式学习(十五):策略模式

设计模式学习(十五):策略模式 作者:Grey 原文地址: 博客园:设计模式学习(十五):策略模式 CSDN:设计模式学习(十五):策略模式 策略模式 策略模式是一种行为型模式,它定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。 以实例来说明 假设我们有一个猫类,这个类里面有体重和身高

设计模式学习(十七):状态模式

设计模式学习(十七):状态模式 作者:Grey 原文地址: 博客园:设计模式学习(十七):状态模式 CSDN:设计模式学习(十七):状态模式 状态模式 状态模式是一种行为型模式。 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。 举例说明: Person 有 Cry ,