设计模式原型模式
Posted Kant101
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式原型模式相关的知识,希望对你有一定的参考价值。
1. 概述
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
2. UML图
原型模式的核心就是原型类 ProtoType,ProtoType 类需要具备以下两个条件:
- (1) 实现 Cloneable 接口:在 Java 中 Cloneable 接口的作用就是在运行时通知虚拟机可以安全地在实现了 Cloneable 接口的类上使用 clone() 方法,只有在实现了 Cloneable 接口的类才可以被拷贝,否则在运行时会抛出 CloneNotSupportedException 异常;
- (2) 重写 Object 类中的 clone() 方法:在 Java 中所有的父类都是 Object,Object中有一个 clone() 方法用于返回对象的拷贝,但是其作用域是 protected,一般的类无法调用,因此,ProtoType类需要将 clone() 方法的作用域修改为 public;
原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式。在实际应用中,原型模式很少单独出现,经常与其他模式混用,它的原型类Prototype 也常用抽象类来替代。
3. 代码与测试
Prototype
package com.design.pattern.prototype;
/**
* @author albert.tan
* @date 2022/11/23
*/
public abstract class Prototype implements Cloneable
protected OtherObject otherObject = new OtherObject(123456789L);
@Override
protected Object clone() throws CloneNotSupportedException
return super.clone();
public abstract void show();
OtherObject
package com.design.pattern.prototype;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author albert.tan
* @date 2022/11/23
*/
@Data
@AllArgsConstructor
public class OtherObject implements Cloneable
private Long id;
@Override
protected Object clone() throws CloneNotSupportedException
return super.clone();
ConcretePrototype
package com.design.pattern.prototype;
/**
* @author albert.tan
* @date 2022/11/23
*/
public class ShallowClone extends Prototype
@Override
protected Object clone() throws CloneNotSupportedException
Prototype prototype = null;
try
prototype = (Prototype) super.clone();
catch (CloneNotSupportedException e)
e.printStackTrace();
return prototype;
@Override
public void show()
System.out.println("浅克隆");
package com.design.pattern.prototype;
/**
* @author albert.tan
* @date 2022/11/23
*/
public class DeepClone extends Prototype
@SuppressWarnings("unchecked")
@Override
protected Prototype clone() throws CloneNotSupportedException
Prototype prototype = null;
try
prototype = (Prototype) super.clone();
catch (CloneNotSupportedException e)
e.printStackTrace();
if (prototype == null) return null;
// 递归调用 clone() 方法克隆 Prototype 中的引用类成员
prototype.otherObject = (OtherObject) this.otherObject.clone();
return prototype;
@Override
public void show()
System.out.println("深克隆");
测试
package com.design.pattern.prototype;
/**
* @author albert.tan
* @date 2022/11/23
*/
public class Client
public static void main(String[] args) throws CloneNotSupportedException
ShallowClone obj1 = new ShallowClone();
ShallowClone obj2 = (ShallowClone) obj1.clone();
System.out.println("obj1 == obj2? " + (obj1 == obj2));
obj2.show();
System.out.println(obj1.otherObject == obj2.otherObject);
System.out.println("========================");
DeepClone obj3 = new DeepClone();
DeepClone obj4 = (DeepClone) obj3.clone();
System.out.println("obj3 == obj4? " + (obj3 == obj4));
obj4.show();
System.out.println(obj3.otherObject == obj4.otherObject);
4. 运用场景与注意事项
优点与适用场景
(1) 原型模式比 new 方法创建对象的性能要好得多,因为 Object 类的 clone() 方法是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显;
(2) 简化对象的创建
所以原型模式适合在重复地创建相似对象的场景使用,比如在一个循环体内创建对象,加入对象创建过程比较复杂或者循环次数很多的话,使用原型模式补单可以简化创建过程,而且也可以提升系统的整体性能。
注意事项
(1) 使用原型模式复制对象不会调用类的构造函数,对象是通过调用 Object 类的 clone() 方法来完成的,它直接在内存中复制数据。补单构造函数不会执行,甚至连访问权限都对原型模式无效。单例模式中,需要将构造函数的访问权限设置为 private,但是 clone() 方法直接无视构造方法的权限,所以单例模式与原型模式冲突,在使用时需要注意;
(2) 深拷贝与浅拷贝。Object 类的 clone() 方法只会拷贝对象中的基本数据类型(8种基本数据类型: byte, char, short, int, long, float, double, boolean 和 对应的封装类),对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。
- 浅拷贝:只克隆对象中的基本数据类型,而不会克隆数组、容器、引用对象等。换言之,浅拷贝仅仅复制所拷贝的对象,而不复制它所引用的对象。如果变量为 String 字符串,则拷贝其引用地址,但是在修改的时候,它会从字符串常量池生成一个新的字符串,原有的字符串对象保持不变;
- 深考本:把要拷贝的对象所引用的对象都克隆一遍。
参考文献
[1] https://blog.csdn.net/a745233700/article/details/83625951
以上是关于设计模式原型模式的主要内容,如果未能解决你的问题,请参考以下文章