您的位置:首页 > 新闻 > 会展 > 技术成神之路:设计模式(三)原型模式

技术成神之路:设计模式(三)原型模式

2024/10/11 21:23:17 来源:https://blog.csdn.net/WriteBug001/article/details/140150483  浏览:    关键词:技术成神之路:设计模式(三)原型模式

1. 定义


原型模式(Prototype Pattern)是一种创建型设计模式,旨在通过复制现有对象来创建新对象,而不是通过实例化类的方式。这个模式可以提高对象创建的效率,尤其是在创建对象的过程非常复杂或代价高昂时。

2. 结构


原型模式包含以下角色:

  • Prototype(原型接口):用于声明克隆自身的方法。通常这个接口会定义一个名为clone的抽象方法。
  • ConcretePrototype(具体原型类):实现原型接口,并实现克隆自身的方法。这类对象可以被克隆。
  • Client(客户端):使用原型接口来克隆新的对象。

UML类图:
在这里插入图片描述

3. 示例代码


// 原型接口
interface Prototype extends Cloneable {Prototype clone();
}// 具体原型类A
class ConcretePrototypeA implements Prototype {private String name;public ConcretePrototypeA(String name) {this.name = name;}@Overridepublic Prototype clone() {try {return (Prototype) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();return null;}}@Overridepublic String toString() {return "ConcretePrototypeA{name='" + name + "'} hashcode= "+ hashCode();}
}// 具体原型类B
class ConcretePrototypeB implements Prototype {private int value;public ConcretePrototypeB(int value) {this.value = value;}@Overridepublic Prototype clone() {try {return (Prototype) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();return null;}}@Overridepublic String toString() {return "ConcretePrototypeB{value=" + value + "} hashcode= "+ hashCode();}
}

测试:

@Testpublic void test() {ConcretePrototypeA prototypeA = new ConcretePrototypeA("Prototype A");ConcretePrototypeB prototypeB = new ConcretePrototypeB(42);Prototype clonedPrototypeA = prototypeA.clone();Prototype clonedPrototypeB = prototypeB.clone();System.out.println("原型A: "+prototypeA);System.out.println("克隆A: "+clonedPrototypeA);System.out.println("原型B: "+prototypeB);System.out.println("克隆B: "+clonedPrototypeB);}

打印:

原型A: ConcretePrototypeA{name='Prototype A'} hashcode= 1823541245
克隆A: ConcretePrototypeA{name='Prototype A'} hashcode= 1020154737
原型B: ConcretePrototypeB{value=42} hashcode= 398457879
克隆B: ConcretePrototypeB{value=42} hashcode= 1850954068

4. 应用场景


  • 对象的创建开销很大:通过克隆现有对象而不是重新创建,可以节省时间和资源。
  • 系统需要大量类似对象:通过克隆原型对象,可以快速生成多个相似但独立的对象。
  • 对象的状态需要动态改变:通过克隆原型对象,可以创建具有特定状态的新对象。

情景回顾:

原型模式在实际应用中可能并不常见,或许你见到过但没留意,因为它的应用场景太少了,让我想起了在写一个多任务下载模块时,每下载一个文件其都有对应的mode,记录一些下载信息状态信息等内容,再进行更新进度的时候需要把这个对象发送出去,通知外界更新UI,有一个问题就是下载中操作的对象和发送出去的对象是同一个,就会出现异常现象,我发送出去的下载进度是90%,UI还没来得及更新,这边又将进度修改为95%了,emm… 可能我描述的问题,你觉的不严重,但这种不可预测的现象是我们不希望发生的。
其中解决方式一 就是克隆一个对象,让UI显示的和下载操作的对象互不干扰,这时如果你new一个新对象的话相比克隆就劣势就凸显出来了。

5. 优缺点


优点:

  • 提高对象创建效率:避免了复杂对象的重复创建,通过克隆现有对象来生成新对象。
  • 动态创建对象:可以在运行时动态创建对象,而无需了解具体的类。
  • 减少子类的数量:通过克隆原型对象,可以减少创建子类的数量,增强系统的灵活性。

缺点:

  • 深拷贝和浅拷贝问题:在涉及复杂对象时,深拷贝和浅拷贝的问题需要特别注意。如果对象包含对其他对象的引用,浅拷贝可能不够用,需要实现深拷贝。
  • 克隆方法的实现复杂:对于一些复杂的对象,克隆方法的实现可能比较复杂,需要处理对象间的依赖关系。

6. 深拷贝与浅拷贝


在原型模式中,克隆可以分为浅拷贝和深拷贝:

  • 浅拷贝:复制对象时,只复制对象本身,而不复制对象所引用的其他对象。也就是说,复制后的对象与原对象共享对其他对象的引用。
  • 深拷贝:复制对象时,不仅复制对象本身,还复制对象所引用的其他对象。这样,复制后的对象与原对象是完全独立的,不共享任何引用。

7. 深拷贝与浅拷贝示例


// 原型接口
interface Prototype extends Cloneable {Prototype clone();
}// 具体原型类
class ConcretePrototype implements Prototype {private String name;private List<String> list;public ConcretePrototype(String name) {this.name = name;this.list = new ArrayList<>();}public void addToList(String item) {list.add(item);}public List<String> getList() {return list;}@Overridepublic Prototype clone() {try {ConcretePrototype copy = (ConcretePrototype) super.clone();// 深拷贝 -测试浅拷贝时注释下面代码!!!copy.list = new ArrayList<>(this.list);return copy;} catch (CloneNotSupportedException e) {e.printStackTrace();return null;}}@Overridepublic String toString() {return "ConcretePrototype{name='" + name + "', list=" + list + "} list hashcode=" + list.hashCode();}
}

测试:

    @Testpublic void test() {ConcretePrototype prototype = new ConcretePrototype("Prototype");prototype.addToList("Item1");prototype.addToList("Item2");// 浅拷贝示例ConcretePrototype shallowClone = (ConcretePrototype) prototype.clone();// 添加新项到原型对象的列表prototype.addToList("Item3");System.out.println("原型: " + prototype);System.out.println("浅拷贝: " + shallowClone);// 深拷贝示例ConcretePrototype deepClone = (ConcretePrototype) prototype.clone();// 添加新项到深拷贝对象的列表deepClone.addToList("Item4");System.out.println("原型: " + prototype);System.out.println("深拷贝: " + deepClone);}

测试浅拷贝打印:

原型: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142
浅拷贝: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142

可以看出两个对象所引用的list对象为同一个

测试深拷贝打印:

原型: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142
深拷贝: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3, Item4]} list hashcode=-1296039165

两个对象引用的list完全不一样了,操作互不影响

8. 设计模式的比较


原型模式与其他创建型设计模式(如工厂模式、抽象工厂模式、单例模式等)有其独特之处:

  • 与工厂模式的区别:工厂模式通过提供一个方法来创建对象,而原型模式通过复制现有对象来创建新的对象。工厂模式适合对象创建过程简单但需要解耦对象创建过程的场景,而原型模式适合对象创建过程复杂且需要高效创建对象的场景。
  • 与单例模式的区别:单例模式确保一个类只有一个实例,而原型模式则允许通过克隆来创建多个实例。它们解决的问题不同,前者关注的是实例的唯一性,后者关注的是高效创建对象。

9. 结论


原型模式是一种高效的对象创建模式,它通过克隆现有对象来创建新对象,避免了通过构造函数创建对象的高昂代价,尽管原型模式在许多方面具有优势,但在实现过程中需要注意对象间的引用关系,确保深拷贝和浅拷贝的正确实现,以避免不必要的资源浪费和潜在的错误。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com