笔头云 笔头云
首页
设计模式
SQL教程
Redis
归档
关于
友链

笔头云

非淡泊无以明志,非宁静无以致远。
首页
设计模式
SQL教程
Redis
归档
关于
友链
  • 设计原则
  • 设计模式
  • 单例模式
  • 工厂模式
  • 建造者模式
  • 原型模式
    • 定义
    • 结构
    • 优点
    • 缺点
    • 应用场景
    • 示例代码
  • 适配器模式
  • 代理模式
  • 装饰器模式
  • 门面模式
  • 桥接模式
  • 享元模式
  • 组合模式
  • 策略模式
  • 模板方法模式
  • 观察者模式
  • 责任链模式
  • 状态模式
  • 迭代器模式
  • 访问者模式
  • 中介模式
  • 命令模式
  • 解释器模式
  • 备忘录模式
  • 设计模式
笔头云
2023-11-10
目录

原型模式

# 原型模式

# 定义

原型模式是一种创建型设计模式,其目的是通过复制现有对象来创建新对象,而不是通过实例化类来创建对象。它允许我们通过克隆(或复制)现有对象来创建新对象,从而避免了使用常规的实例化方法。
原型模式是原型对象的复制。可以通过浅拷贝或深拷贝来实现复制操作。浅拷贝只复制对象的基本数据类型和引用,而深拷贝会递归地复制对象的所有属性和关联对象。

深拷贝和浅拷贝

浅拷贝:创建一个新对象,将基本数据类型如int、float、String等,直接复制字段值到新的对象中,引用类型数据复制引用对象的地址到新对象中,新对象和原始对象共享同一个引用对象,其中一个修改会影响到另一个对象。
深拷贝:创建一个新对象,将基本数据类型和引用类型都完全复制一份到新对象中,深拷贝会递归复制引用类型字段指向的对象,新对象和旧对象的引用对象完全独立、互不影响。

# 结构

抽象原型类:可以是接口或基类,声明clone方法,在简单情况下可以不用抽象原型类,直接用具体原型类就可以。
具体原型类:实现或扩展clone方法,返回基类的抽象原型对象。

原型模式

- img: https://bitouyun.com/images/design-pattern/prototype.png
  link: https://bitouyun.com/images/design-pattern/prototype.png
  name: 原型模式
1
2
3

# 优点

原型模式通过复制现有对象来创建新对象,减少了对象的创建成本,提高了对象的创建速度,并且具有灵活性和封装性。

# 缺点

浅拷贝和深拷贝,一旦使用不正确,就会造成bug。如果系统中存在多个具体原型类,每个类都需要实现克隆方法,这可能会导致代码的重复。

# 应用场景

当需要创建的对象的成本较高时,如:使用new生成一个对象需要非常繁琐的过程(依赖外部资源、数据准备、访问权限等)、构造函数比较复杂、在循环中产生大量对象等,可以使用原型模式。

# 示例代码

场景:

克隆对象:深拷贝和浅拷贝

    /**
     * 原型接口
     * 简单场景可以不用原型接口,直接使用具体类
     */
    public interface Prototype {
      Prototype clone();
    }
    
    1
    2
    3
    4
    5
    6
    7
    /**
     * 具体需要克隆的类
     * 浅克隆(拷贝),基本数据类型复制字段值,引用类型对象复制地址
     */
    @Data
    public class ConcretePrototype implements Prototype {
    
      private String name;
      private int age;
      private List<String> hobbies;
    
      @Override
      public Prototype clone() {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setName(this.name);
        concretePrototype.setAge(this.age);
        concretePrototype.setHobbies(this.hobbies);
        return concretePrototype;
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
     * 测试类
     */
    @Slf4j
    public class Client {
    
      public static void main(String[] args) {
        // 创建原始对象
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setName("小明");
        concretePrototype.setAge(8);
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("游泳");
        hobbies.add("画画");
        concretePrototype.setHobbies(hobbies);
        log.info("原始对象:{}", concretePrototype);
    
        // 克隆新对象 - 浅拷贝
        ConcretePrototype concretePrototypeClone = (ConcretePrototype) concretePrototype.clone();
        log.info("原始对象的爱好:{}", concretePrototype.getHobbies());
        log.info("新对象的爱好:{}", concretePrototypeClone.getHobbies());
        // true 浅克隆,对象地址相同
        log.info("原始对象和新对象引用对象地址是否相同:{}", concretePrototype.getHobbies() == concretePrototypeClone.getHobbies());
      }
    }
    
    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
    /**
     * 具体需要克隆的类
     * 深克隆(拷贝),基本类型和引用类型都会完全复制一份。
     */
    @Data
    public class ConcretePrototypeDeep implements Serializable {
    
      private String name;
      private int age;
      private List<String> hobbies;
    
      @SneakyThrows
      @Override
      public Object clone() {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        // 写入当前对象
        oos.writeObject(this);
    
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    /**
     * 测试类
     */
    @Slf4j
    public class Client2 {
    
      public static void main(String[] args) {
        // 创建原始对象
        ConcretePrototypeDeep concretePrototypeDeep = new ConcretePrototypeDeep();
        concretePrototypeDeep.setName("小明");
        concretePrototypeDeep.setAge(8);
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("游泳");
        hobbies.add("画画");
        concretePrototypeDeep.setHobbies(hobbies);
        log.info("新对象:{}", concretePrototypeDeep);
    
        // 克隆新对象 - 深拷贝
        ConcretePrototypeDeep concretePrototypeClone = (ConcretePrototypeDeep) concretePrototypeDeep.clone();
        log.info("原始对象的爱好:{}", concretePrototypeDeep.getHobbies());
        log.info("新对象的爱好:{}", concretePrototypeClone.getHobbies());
        // false 深拷贝,对象地址不相同
        log.info("原始对象和新对象引用地址是否相同:{}", concretePrototypeDeep.getHobbies() == concretePrototypeClone.getHobbies());
      }
    }
    
    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
    // Make sure to add code blocks to your code group
    #创建型模式#设计模式
    上次更新: 2023/11/17, 09:38:49
    建造者模式
    适配器模式

    ← 建造者模式 适配器模式→

    最近更新
    01
    FRP内网穿透docker部署 工具
    05-07
    02
    Office Util办公工具 工具
    01-14
    03
    Git常用命令
    01-16
    更多文章>
    Theme by Vdoing | Copyright © 2023-2025 鲁ICP备2023014898号 公安备案号:37020302372159
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×