• 原型设计模式


    原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制(克隆)现有对象来创建新对象,而无需显式地使用构造函数创建新对象。这种模式通常用于创建成本较高或复杂的对象,以避免重复的初始化工作。

    结构

    1. 原型接口(Prototype Interface):通常需要创建一个原型接口,该接口定义了一个clone方法,用于复制对象。所有需要支持克隆操作的类都需要实现这个接口。
    2. 具体原型(Concrete Prototype):具体原型类是实现了原型接口的类,它实际上进行对象的复制操作。具体原型类需要实现clone方法来克隆自身。
    3. 客户端(Client):客户端代码通过原型接口来请求克隆操作(即使用具体原型类中的clone()方法来复制新对象),而不需要知道具体的对象创建细节。

    实现

    原型模式可以分为浅克隆深克隆两种形式,取决于复制的方式。

    • 浅克隆:创建一个新对象,新对象的属性与原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
    • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有的对象地址。

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

    class Prototype implements Cloneable{
        public Prototype() {
            System.out.println("创建具体的原型对象");
        }
    
        @Override
        protected Prototype  clone() throws CloneNotSupportedException {
            System.out.println("复制成功!");
            return (Prototype) super.clone();
        }
    }
    
    public class PrototypeDemo {
        public static void main(String[] args) throws CloneNotSupportedException{
            Prototype original = new Prototype();
    
            Prototype clone = original.clone();
    
            System.out.println(original == clone); //false
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    上面的方法很简单,当然,还有另外一种方法,就是自己创建原型接口,按照上面的原型模式的结构来实现

    // 原型接口
    interface Prototype {
        Prototype clone();
    }
    
    // 具体原型类
    class ConcretePrototype implements Prototype {
        private String data;
    
        public ConcretePrototype(String data) {
            this.data = data;
        }
    
        @Override
        public Prototype clone() {
            return new ConcretePrototype(this.data);
        }
    
        public String getData() {
            return data;
        }
    }
    
    public class PrototypeDemo {
        public static void main(String[] args) {
            // 创建一个具体原型对象
            Prototype original = new ConcretePrototype("Hello, world!");
    
            // 克隆原型对象来创建新对象
            Prototype clone = original.clone();
    
            // 输出原型和克隆对象的数据
            System.out.println("Original Data: " + ((ConcretePrototype) original).getData());
            System.out.println("Clone Data: " + ((ConcretePrototype) clone).getData());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    使用场景

    原型模式使用场景有:

    1. 对象的创建成本较高:如果创建一个对象的成本很高,例如需要从数据库中加载大量数据或进行复杂的计算,那么使用原型模式可以避免多次创建相同的对象,而是通过克隆已有对象来创建新对象,从而提高性能。

    2. 对象的创建过程复杂:当对象的创建过程非常复杂,包括多个步骤或依赖于其他对象时,使用原型模式可以简化代码,因为您只需克隆一个已有对象,而不必重复执行复杂的创建步骤。

    3. 需要保持对象的不变性:有些对象需要保持不变性,即不能通过直接赋值属性的方式修改其状态。原型模式可以帮助您创建对象的副本,而不会影响原始对象的状态。

    4. 大量相似对象的创建:当需要创建大量相似但略有差异的对象时,原型模式非常有用。您可以创建一个原型对象,然后根据需要克隆该对象并进行适当的修改。

    5. 支持动态配置对象:原型模式允许您在运行时动态配置对象,通过克隆已有对象并进行修改,而不必硬编码不同的配置选项。

    6. 减少子类的创建:在某些情况下,如果您有多个子类,而这些子类只有一些差异,可以使用原型模式来创建这些子类的实例,而不必为每个子类都创建一个独立的类。

    深克隆

    在实现深克隆时,有几种常见的方式:

    1. 手动实现深克隆:这是最基本的方式,开发人员需要手动编写代码来遍历原始对象的属性和子对象,并创建相应的新对象来存储复制后的数据。这通常涉及递归操作,以确保所有嵌套对象也被深克隆。
    class Address implements Cloneable {
        private String street;
        private String city;
    
        public String getStreet() {
            return street;
        }
    
        public void setStreet(String street) {
            this.street = street;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        public Address(String street, String city) {
            this.street = street;
            this.city = city;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    class Person implements Cloneable {
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
        public Person(String name, Address address) {
            this.name = name;
            this.address = address;
        }
    
        private String name;
        private Address address;
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Person clonedPerson = (Person) super.clone();
            clonedPerson.address = (Address) address.clone();
            return clonedPerson;
        }
    }
    
    public class Main {
        public static void main(String[] args) throws CloneNotSupportedException {
            Address address = new Address("步行街", "北京");
            Person originalPerson = new Person("Alice", address);
    
            Person clonedPerson = (Person) originalPerson.clone();
    
            System.out.println(originalPerson.getName()+"   "+originalPerson.getAddress().getStreet()); // Alice   步行街
            clonedPerson.setName("Bob");
            clonedPerson.getAddress().setStreet("人民公园");
            System.out.println(clonedPerson.getName()+"   "+clonedPerson.getAddress().getStreet());   // Bob   人民公园
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    1. 使用序列化和反序列化:这种方式需要将原始对象序列化为一个字节流,然后再将其反序列化为新对象。这可以通过语言内置的序列化机制或第三方库来实现。在这个过程中,对象的所有属性和嵌套对象都会被复制。
    import java.io.*;
    
    class Address implements Serializable {
        private String street;
        private String city;
    
        public String getStreet() {
            return street;
        }
    
        public void setStreet(String street) {
            this.street = street;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        public Address(String street, String city) {
            this.street = street;
            this.city = city;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    class Person implements Serializable  {
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
        public Person(String name, Address address) {
            this.name = name;
            this.address = address;
        }
    
        private String name;
        private Address address;
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Person clonedPerson = (Person) super.clone();
            clonedPerson.address = (Address) address.clone();
            return clonedPerson;
        }
    }
    
    public class Main {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            Address address = new Address("步行街", "北京");
            Person originalPerson = new Person("Alice", address);
    
            // 序列化主类
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(originalPerson);
    
            // 反序列化创造克隆类
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Person clonedPerson = (Person) ois.readObject();
    
            System.out.println(originalPerson.getName()+"   "+originalPerson.getAddress().getStreet()); // Alice   步行街
            clonedPerson.setName("Bob");
            clonedPerson.getAddress().setStreet("人民公园");
            System.out.println(clonedPerson.getName()+"   "+clonedPerson.getAddress().getStreet());   // Bob   人民公园
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
  • 相关阅读:
    微软surface laptop禁用触摸屏(win10、设备管理器)
    1054 The Dominant Color
    算法笔记-第十章-图的遍历(未处理完-11.22日)
    常用MII接口详解
    MySQL 锁机制
    秩零化度定理(Rank-Nullity Theorem)
    Flink学习之flink sql
    Centos7 Shell编程之正则表达式、文本处理工具
    一种HNR与路由交换设备间信令协议的设计与实现
    River Locks
  • 原文地址:https://blog.csdn.net/qq_73574147/article/details/136135823