《设计模式详解》创建型模式 - 原型模式

简介: 创建型模式 - 原型模式
完整的笔记目录: 《设计模式详解》笔记目录,欢迎指点!

创建型模式的主要关注点是:怎样创建对象?,它的主要特点是:将对象的创建与使用分离

这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。

创建型模式分为:

  • 单例模式
  • 工厂方法模式
  • 抽象工程模式
  • ==原型模式==
  • 建造者模式

4.3 原型模式

4.3.1 概述

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

4.3.2 结构

原型模式包含如下角色:

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

接口类图如下:

在这里插入图片描述

4.3.3 实现

原型模式的克隆分为浅克隆和深克隆。

浅克隆:创建一个新对象,新对象的属性和原对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

浅克隆类似 “快捷方式”,深克隆才是真正的 “复制文件”。

Java 中的 Object 类中提供了 clone() 方法来实现浅克隆

Java 中的 Cloneable 接口是上面类图中的抽象原型类,而实现了 Cloneable 接口的子实现类就是具体的原型类。

Realizetype:具体的原型类

public class Realizetype implements Cloneable {

    public Realizetype() {
        System.out.println("具体的原型对象创建完成!");
    }

    @Override
    protected Realizetype clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return (Realizetype) super.clone();
    }
}

PrototypeTest:测试访问类

public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Realizetype r1 = new Realizetype(); // 原型对象
        Realizetype r2 = r1.clone(); // 克隆出来的对象
        System.out.println("对象r1和r2是同一个对象?" + (r1 == r2));
    }
}

运行结果:clone 原型对象的时候,不会调用构造方法,因为该对象不是通过 new 创建的

具体的原型对象创建完成!
具体原型复制成功!
对象r1和r2是同一个对象?false

4.3.4 案例

【例】使用原型模式生成 “三好学生” 奖状。

同一学校的 “三好学生” 奖状除了获奖人姓名不同,其他都相同,可以使用原型模式复制多个“三好学生”奖状出来,然后修改奖状上的名字即可。

类图如下:

在这里插入图片描述

代码如下:

/**
 * 奖状类
 */
@Data
public class Citation implements Cloneable {
    private String name; // 奖状上的名字

    public void show() {
        System.out.println(name + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}
/**
 * 测出访问类
 */
public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation c1 = new Citation();
        c1.setName("张三");

        // 复制奖状
        Citation c2 = c1.clone();
        c2.setName("李四"); // 将奖状的名字改为李四

        c1.show();
        c2.show();
    }
}

4.3.5 使用场景

以下两种情况,可以使用原型模式快捷的创建对象:

  • 对象的创建非常复杂。
  • 性能和安全要求比较高。

4.3.6 扩展 - 深克隆

引用对象的浅克隆

将上面的 “三好学生” 奖状的案例中 Citation 类的 name 属性修改为 Student 类型的属性。

/**
 * 学生类
 */
@Data
public class Student {
    private String name;
    public Student(String name) {
        this.name = name;
    }
}
/**
 * 奖状类
 */
@Data
public class Citation implements Cloneable {
    private Student stu; // 这是个引用对象

    void show() {
        System.out.println(stu.getName() + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}
public class CitationTest {
    public static void main(String[] args) throws Exception {
        // 原型对象
        Citation c1 = new Citation();
        Student stu1 = new Student("张三");
        c1.setStu(stu1);

        // 复制奖状并修改名字
        Citation c2 = c1.deepClone();
        Student stu2 = c2.getStu();
        stu2.setName("李四");

        // 判断stu1对象和stu2对象是否是同一个对象
        System.out.println("st1和stu2是否同一个对象?" + (stu1 == stu2));

        c1.show();
        c2.show();
    }
}

运行结果:stu1 和 stu2 是同一个对象

st1和stu2是否同一个对象?true
李四同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!
李四同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!

stu1 和 stu2 是同一个对象,就会产生将 stu1 中 name 属性值改为 “李四”,两个 Citation 对象中显示的都是李四。

这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。

这种情况需要使用深克隆,而进行深克隆需要使用对象流。

实现 1:文件流 + 对象流

学生类(Student)同上,但是要实现 Serializable 接口。

奖状类(Citation)实现 Serializable 接口,定义一个 deepClone 方法,通过文件输出流流和对象流实现深克隆。

// 1 所有对象都实现序列化的接口
// 2 自定义一个深度克隆方法deepClone, 通过文件流和对象流的方式实现对象的深度拷贝
public Citation deepClone() throws Exception {
  try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
       ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));) {
    oos.writeObject(this);
    Citation citation = (Citation) ois.readObject();
    return citation;
  }
}

实现 2:字节数组流 + 对象流

学生类(Student)同上,实现 Serializable 接口。

奖状类(Citation)实现 Serializable 接口,定义一个 deepClone 方法,通过字节数组流和对象流实现深克隆。

// 1 所有对象都实现序列化的接口
// 2 自定义一个深度克隆方法deepClone, 通过字节数组流和对象流的方式实现对象的深度拷贝
public Citation deepClone2() throws Exception {
  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 (Citation) ois.readObject();
  }
}

测试

以上两种方法都可以实现深克隆:

public class CitationTest {
    public static void main(String[] args) throws Exception {
        // 原型对象
        Citation c1 = new Citation();
        Student stu1 = new Student("张三");
        c1.setStu(stu1);

        // 复制奖状并修改名字
        Citation c2 = c1.deepClone();
        Student stu2 = c2.getStu();
        stu2.setName("李四");

        // 判断stu1对象和stu2对象是否是同一个对象
        System.out.println("st1和stu2是否同一个对象?" + (stu1 == stu2));

        c1.show();
        c2.show();
    }
}

运行结果:

st1和stu2是否同一个对象?false
张三同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!
李四同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!
相关文章
|
2月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
【Java笔记+踩坑】设计模式——原型模式
|
2月前
|
设计模式 Java
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
|
3月前
|
设计模式 存储 负载均衡
【五】设计模式~~~创建型模式~~~单例模式(Java)
文章详细介绍了单例模式(Singleton Pattern),这是一种确保一个类只有一个实例,并提供全局访问点的设计模式。文中通过Windows任务管理器的例子阐述了单例模式的动机,解释了如何通过私有构造函数、静态私有成员变量和公有静态方法实现单例模式。接着,通过负载均衡器的案例展示了单例模式的应用,并讨论了单例模式的优点、缺点以及适用场景。最后,文章还探讨了饿汉式和懒汉式单例的实现方式及其比较。
【五】设计模式~~~创建型模式~~~单例模式(Java)
|
3月前
|
设计模式 XML 存储
【三】设计模式~~~创建型模式~~~抽象工厂模式(Java)
文章详细介绍了抽象工厂模式,这是一种创建型设计模式,用于提供一个接口以创建一系列相关或相互依赖的对象,而不指定它们具体的类。通过代码示例和结构图,文章展示了抽象工厂模式的动机、定义、结构、优点、缺点以及适用场景,并探讨了如何通过配置文件和反射机制实现工厂的动态创建。
【三】设计模式~~~创建型模式~~~抽象工厂模式(Java)
|
3月前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
|
3月前
|
设计模式 XML Java
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
文章详细介绍了简单工厂模式(Simple Factory Pattern),这是一种创建型设计模式,用于根据输入参数的不同返回不同类的实例,而客户端不需要知道具体类名。文章通过图表类的实例,展示了简单工厂模式的结构、时序图、代码实现、优缺点以及适用环境,并提供了Java代码示例和扩展应用,如通过配置文件读取参数来实现对象的创建。
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
|
3月前
|
设计模式 存储 XML
[设计模式]创建型模式-抽象工厂模式
[设计模式]创建型模式-抽象工厂模式
|
3月前
|
设计模式 测试技术 Go
[设计模式]创建型模式-简单工厂模式
[设计模式]创建型模式-简单工厂模式
|
3月前
|
设计模式 XML 存储
【四】设计模式~~~创建型模式~~~建造者模式(Java)
文章详细介绍了建造者模式(Builder Pattern),这是一种创建型设计模式,用于将复杂对象的构建与其表示分离,允许分步骤创建一个复杂的对象而无需指定其内部的具体构造细节。通过定义抽象建造者、具体建造者、指挥者和产品角色,建造者模式允许通过相同的构建过程创建不同的产品表示,提高了系统的灵活性和扩展性。
|
4月前
|
设计模式
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么