首页 > 其他分享 >设计模式-原型模式

设计模式-原型模式

时间:2022-11-12 18:32:08浏览次数:35  
标签:family name concretePrototypeB age 模式 原型 设计模式 public ConcretePrototypeB

原型模式的核心在于拷贝源对象,UML类图如下:

设计模式-原型模式_创建对象

其中主要有三个角色:

  1. 客户(client):客户类提出创建对象的请求
  2. 抽象原型(Prototype):规定拷贝接口
  3. 具体原型(ConcreatePrototyoe):被拷贝对象

原型模式通用写法

public interface Prototype<T> {
Prototype<T> clone();
}
复制代码
public class ConcretePrototypeB implements Prototype{

private String name;
private Integer age;

public String getName() {
return name;
}

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

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

@Override
public ConcretePrototypeB clone() {
ConcretePrototypeB concretePrototypeB = new ConcretePrototypeB();
concretePrototypeB.setName(this.name);
concretePrototypeB.setAge(this.age);
return concretePrototypeB;
}

@Override
public String toString() {
return "ConcretePrototypeB{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) {
ConcretePrototypeB concretePrototypeB = new ConcretePrototypeB();
concretePrototypeB.setName("张三");
concretePrototypeB.setAge(19);
ConcretePrototypeB concretePrototypeB_copy = concretePrototypeB.clone();

System.out.println(concretePrototypeB);
System.out.println(concretePrototypeB_copy);

}
}

设计模式-原型模式_原型模式_02

上述的例子就是最简单的原型模式,可能有些人会觉得在里面set值和在外面好像一样只不过将对象创建设置的方法移到里面​​clone​​方法里面了而已,话虽然是这么说,的确看到的也是这样,但是有些对象的变量是私有的外部是不能访问的,此时再外部进行实例化然后在进行复制那么必然一些私有的变量是没有办法复制的。所以还是有一点点差别的。

通过这个例子再说一下原型模式,用通俗点话来讲其实就是在你不是通过在外部使用new​ 关键字来创建对象而是使用拷贝对象调用内部克隆方法创建的类的模式就是原型模式

但是大部分的克隆并不是像上文中的实现方式一样,一般都是直接基于内存二进制流进行拷贝,无需在经历夯实的对象初始化过程(不调用构造函数),这样性能提升很多,当对象构建过程比较耗时是,可以利用当前系统中已存在的对象作为原型,对其进行克隆

原型模式实现改造(实现Cloneable接口)

public class ConcretePrototypeB implements Cloneable{

private String name;
private Integer age;

private List<String> family;

public String getName() {
return name;
}

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

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public List<String> getFamily() {
return family;
}

public void setFamily(List<String> family) {
this.family = family;
}

@Override
public ConcretePrototypeB clone() {
ConcretePrototypeB clone = null;
try {
clone = (ConcretePrototypeB) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
return clone;
}

@Override
public String toString() {
return "ConcretePrototypeB{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
复制代码

只需要实现​​Cloneable​​接口实现以下​​clone​​方法即可这样对于很复杂的对象赋值其实就很简单了

不过这里也有个小问题如下:

public class Test {
public static void main(String[] args) {
ConcretePrototypeB concretePrototypeB = new ConcretePrototypeB();
concretePrototypeB.setName("张三");
concretePrototypeB.setAge(19);
List<String> family = new ArrayList<>();
family.add("爷爷");
family.add("奶奶");
family.add("爸爸");
family.add("妈妈");
family.add("妹妹");
concretePrototypeB.setFamily(family);
ConcretePrototypeB concretePrototypeB_copy = concretePrototypeB.clone();
concretePrototypeB_copy.setName("李四");
concretePrototypeB_copy.getFamily().add("外公");
concretePrototypeB_copy.getFamily().add("外婆");
System.out.println("张三" + concretePrototypeB);
System.out.println("李四" + concretePrototypeB_copy);
}
}
复制代码

设计模式-原型模式_ide_03

上图中的打印结果可以知道​​Cloneable​​接口实现的克隆是浅拷贝,所以我们在该其他对象的时候连带所有的对象都改了

浅拷贝:赋值对象的引用地址,如下图所示:

设计模式-原型模式_原型模式_04

两个指针指向了同一片地址,所以一个修改所有的都修改了

使用序列化实现深度克隆

基于上述的问题我们可以再改造一下添加​​deepClone​​方法如下代码

public ConcretePrototypeB deepClone() {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(this);
ByteArrayInputStream inputStream = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(inputStream);
ConcretePrototypeB deepClone = (ConcretePrototypeB)ois.readObject();
out.close();
oos.close();
inputStream.close();
ois.close();
return deepClone;
}catch (Exception e){
e.printStackTrace();
}
return null;
}

设计模式-原型模式_原型模式_05

原型模式在源码中的应用

设计模式-原型模式_原型模式_06

设计模式-原型模式_创建对象_07

原型模式的优缺点以及应用场景

优点:

  1. 性能优良,Java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象性能上提升了很多
  2. 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用

缺点:

  1. 需要为每个类配置克隆方法
  2. 克隆方法位于类的内部,当对已有类进行改造的时候,需要修改克隆代码,违背开闭原则
  3. 实现深度克隆的时候代码复杂如果设计嵌套类更麻烦

适用场景:

  1. 类初始化消耗资源较多的情况
  2. new的过程很复杂
  3. 构造函数很复杂
  4. 需要循环产生大量对象的时候

我们平常使用的BeanUtils就是原型模式

标签:family,name,concretePrototypeB,age,模式,原型,设计模式,public,ConcretePrototypeB
From: https://blog.51cto.com/u_15773567/5843225

相关文章

  • 设计模式学习(二十一):命令模式
    设计模式学习(二十一):命令模式作者:Grey原文地址:博客园:设计模式学习(二十一):命令模式CSDN:设计模式学习(二十一):命令模式命令模式命令模式是一种行为型模式。通过调用者调用......
  • 设计模式学习(二十):备忘录模式
    设计模式学习(二十):备忘录模式作者:Grey原文地址:博客园:设计模式学习(二十):备忘录模式CSDN:设计模式学习(二十):备忘录模式备忘录模式备忘录模式是一种行为型模式。用于记录对......
  • 设计模式学习(十九):访问者模式
    设计模式学习(十九):访问者模式作者:Grey原文地址:博客园:设计模式学习(十九):访问者模式CSDN:设计模式学习(十九):访问者模式访问者模式访问者模式是一种行为型模式。访问者模式......
  • [Design Patterns] Creational patterns创建型模式
    摘抄:这里最大的障碍在于硬编码被实例化的类。创建型模式提供了不同的方式来去除需要实例化它们的代码中对具体类的显示指定。如果CreateMaze调用虚函数而不是construct......
  • 设计模式学习(十八):迭代器模式
    设计模式学习(十八):迭代器模式作者:Grey原文地址:博客园:设计模式学习(十八):迭代器模式CSDN:设计模式学习(十八):迭代器模式迭代器模式迭代器模式是一种行为型模式。迭代器最典......
  • 设计模式学习(十七):状态模式
    设计模式学习(十七):状态模式作者:Grey原文地址:博客园:设计模式学习(十七):状态模式CSDN:设计模式学习(十七):状态模式状态模式状态模式是一种行为型模式。对象的行为依赖于它的......
  • 设计模式学习(十六):责任链模式
    设计模式学习(十六):责任链模式作者:Grey原文地址:博客园:设计模式学习(十六):责任链模式CSDN:设计模式学习(十六):责任链模式责任链模式责任链模式是一种行为型模式。举例说明:有......
  • 线程协作(生产者消费者模式)
    线程协作(生产者消费者模式)线程通信1.Java提供了几个方法解决线程之间的通信问题​。wait()表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁​......
  • 设计模式学习(十五):策略模式
    设计模式学习(十五):策略模式作者:Grey原文地址:博客园:设计模式学习(十五):策略模式CSDN:设计模式学习(十五):策略模式策略模式策略模式是一种行为型模式,它定义了一组算法,将每个......
  • 动态代理模式下UndeclaredThrowableException的产生
    API文档我们先来看下这个异常类的api文档:Thrownbyamethodinvocationonaproxyinstanceifitsinvocationhandler'sinvokemethodthrowsacheckedexception(a......