设计模式---创建型模式---原型模式

1. 原型模式

1.1 定义

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。

这种模式是实现了一个原型接口,该接口用于创建当前对象的拷贝。当直接创建对象的代价比较大时,则采用这种模式。

例如:淘宝。我们知道,淘宝在双十一期间与普通时间的工作量有很大差别,并且CPU的处理速度和数据库的处理速度不在一个级别,我们不能每次访问都去数据库查询,这可能会导致数据库宕机。所以,我们在这之前,就需要把数据库中的数据全部加载到缓存中,当每次访问时就去缓存中查,判断是否有这个对象,而不去数据库中查询。

1.2 介绍

原型模式主要是用原型实例指定创建对象的种类,通过拷贝原型来创建新的对象。主要是解决在运行期的建立和删除原型

使用场景:1.当一个系统应该独立于它的产品创建,构成和表示时;

​ 2.当要实例化的类是在运行时刻指定时;(如:动态重载)

​ 3.为了避免创建一个与产品类层次平行的工厂类层次时;

​ 4.当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并拷贝它们可能比每次用的合适状态手工实例化该类更方便一些。

原型模式可分为以下角色:

  • 抽象原型类:规定了具体原型对象必须实现clone()方法;
  • 具体原型类:实现了抽象原型类的clone()方法;
  • 访问类:使用具体原型类的clone()方法拷贝对象。

原型模式中拷贝分为浅拷贝和深拷贝:

  • 浅拷贝:浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是指向内存的地址 ,所以如果其中一个对象改变了这个引用类型的值,就会影响到另一个对象。浅拷贝使用默认的clone()方法来实现。
  • 深拷贝:深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。

2.代码介绍

2.1 浅拷贝

抽象原型类

@Slf4j
public abstract class Commodity implements Cloneable {

    protected abstract void purchase();
    
}

具体原型类

@Slf4j
public class Electronics extends Commodity {
    protected String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected void purchase() {
        log.info("购买了"+name+"~~~");
    }

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

访问类

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {

        Electronics electronics = new Electronics();
        Electronics clone = (Electronics) electronics.clone();
        electronics.setName("电脑");
        clone.setName("手机");
        electronics.purchase();
        clone.purchase();
    }
}

/**
 * [main] INFO com.glw.designPattern.dp_5_prototypeMode.浅拷贝.基本类型.Electronics - 购买了电脑~~~
 * [main] INFO com.glw.designPattern.dp_5_prototypeMode.浅拷贝.基本类型.Electronics - 购买了手机~~~
 */

2.2 浅拷贝出现的问题

浅拷贝具体原型对象的属性只能是基本数据类型和String类型, 那么其他类型会发生什么呢???

具体对象类

@Data
public class ConsumerCategory {
    private String name;
}

抽象原型类

@Slf4j
public abstract class Commodity implements Cloneable {

    abstract void purchase();

}

具体原型类

@Slf4j
public class Electronics extends Commodity {
    private ConsumerCategory consumerCategory;

    public ConsumerCategory getConsumerCategory() {
        return consumerCategory;
    }

    public void setConsumerCategory(ConsumerCategory consumerCategory) {
        this.consumerCategory = consumerCategory;
    }

    @Override
    void purchase() {
        log.info("购买了"+consumerCategory.getName()+"~~~");
    }

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

访问类

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {

        Electronics electronics = new Electronics();
        ConsumerCategory consumerCategory = new ConsumerCategory();
        consumerCategory.setName("电脑");
        electronics.setConsumerCategory(consumerCategory);
        Electronics clone = electronics.clone();
        clone.getConsumerCategory().setName("手机");
        electronics.purchase();
        clone.purchase();
    }
}

/**
 * [main] INFO com.glw.designPattern.dp_5_prototypeMode.浅拷贝.对象类型.Electronics - 购买了手机~~~
 * [main] INFO com.glw.designPattern.dp_5_prototypeMode.浅拷贝.对象类型.Electronics - 购买了手机~~~
 */

我们能看到,对于基本类型的数据,得到的是两个对象,但是对于对象类型或者其他类型的数据(这里的例子为对象类型),得到的确实一个结果,即得到的是一个对象,这是为什么呢???

因为Object类中提供了clone()方法实现的是浅拷贝,对于非基本类型属性仍指向原有属性所指向的内存地址,原型类中的ConsumerCategory对象和拷贝类中的对象是同一个对象,当修改拷贝类的ConsumerCategory对象时也会修改原型类中的ConsumerCategory对象。

深拷贝就可以解决这种问题…

2.2 深拷贝

深拷贝实现的两种方式:

  • 重写clone()方法;

  • 通过对象序列化实现,即实现java.io.Serializable接口

    1. 重写clone()方法

      具体对象类

      @Data
      public class ConsumerCategory implements Cloneable {
      
          private String name;
      
          @Override
          protected Object clone() throws CloneNotSupportedException {
              return super.clone();
          }
      }
      

      抽象原型类

      @Slf4j
      public abstract class Commodity implements Cloneable {
      
          abstract void purchase();
      
      }
      

      具体原型类

      @Slf4j
      public class Electronics extends Commodity {
          private ConsumerCategory consumerCategory;
      
          public ConsumerCategory getConsumerCategory() {
              return consumerCategory;
          }
      
          public void setConsumerCategory(ConsumerCategory consumerCategory) {
              this.consumerCategory = consumerCategory;
          }
      
          @Override
          void purchase() {
              log.info("购买了"+consumerCategory.getName()+"~~~");
          }
      
          @Override
          protected Electronics clone() throws CloneNotSupportedException {
              Electronics deepClone =  (Electronics) super.clone();
              deepClone.consumerCategory = (ConsumerCategory) consumerCategory.clone();
              return deepClone;
          }
      }
      

      访问类

      public class Test {
          public static void main(String[] args) throws CloneNotSupportedException {
      
              Electronics electronics = new Electronics();
              ConsumerCategory consumerCategory = new ConsumerCategory();
              consumerCategory.setName("电脑");
              electronics.setConsumerCategory(consumerCategory);
              Electronics clone = electronics.clone();
              clone.getConsumerCategory().setName("手机");
              electronics.purchase();
              clone.purchase();
          }
      }
      
      /**
       * [main] INFO com.glw.designPattern.dp_5_prototypeMode.深拷贝.对象类型.Electronics - 购买了电脑~~~
       * [main] INFO com.glw.designPattern.dp_5_prototypeMode.深拷贝.对象类型.Electronics - 购买了手机~~~
       */
      
    2. 对象序列化

      我们先来了解一下什么是对象序列化与反序列化

      序列化:将数据结构或对象转换成二进制字节流的过程。利用FileOutputStream。进行序列化操作就必须实现Serializable接口。

      反序列化:将在序列化过程中所生成的二进制字节流的过程转换成数据结构或者对象的过程。利用FileInputStream

      在浅拷贝出现的问题的代码基础上进行修改

      具体对象类

      @Data
      public class ConsumerCategory implements Serializable {//......
      }
      

      抽象原型类

      public abstract class Commodity implements Cloneable, Serializable {//......
      }
      

      访问类

      public class Test {
          public static void main(String[] args) throws Exception {
      
              Electronics electronics = new Electronics();
              ConsumerCategory consumerCategory = new ConsumerCategory();
              consumerCategory.setName("电脑");
              electronics.setConsumerCategory(consumerCategory);
              //序列化对象
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
              oos.writeObject(electronics);  //序列化对象
              oos.close(); //关闭对象输出流
              //反序列化对象
              ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
              Electronics clone = (Electronics) ois.readObject();  //反序列化对象
              ois.close();  //关闭对象输入流
              clone.getConsumerCategory().setName("手机");
              electronics.purchase();
              clone.purchase();
          }
      }
      
      /**
       * [main] INFO com.glw.designPattern.dp_5_prototypeMode.浅拷贝.重写clone方法.Electronics - 购买了手机~~~
       * [main] INFO com.glw.designPattern.dp_5_prototypeMode.浅拷贝.重写clone方法.Electronics - 购买了手机~~~
       */
      

3. 原型模型的优缺点

优点:

  1. 性能提高。
  2. 逃避构造函数的约束。

缺点:

  1. 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
  2. 必须实现 Cloneable 接口。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式(Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式(Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值