原型模式(创建型模式)
原创大约 4 分钟
模式概述
原型模式是一种创建型设计模式,它可以复制已有对象,而又无需依赖这些对象所属的类。意思就是可以它照着模子自己克隆
出另一个产品
,这也是它名字的由来。
问题
如果希望生成一个与现有对象完全相同的复制品,该如何实现呢?
首先,必须创建一个属于相同类的对象。
然后,必须遍历原对象的所有属性,并将其值复制到新对象中。
但如果这个要复制的对象的私有成员变量无法访问,该怎么办呢?另外,如果不知道这个复制对象属于什么类,那又该怎么办呢?
方案
原型模式为所有能够被克隆的对象声明了一个通用接口,以便能够克隆对象,而且又无需知道对象属于什么类,以及它有多少私有属性。
这个可以被克隆的对象就叫做 原型。
它的原作方式是:创建一系列不同类型的对象并以不同的方式配置它们。如果所需对象与这个配置对象中的某一个相同,那就可以直接克隆那个配置对象了,而无需以新建的方式得到对象。
结构

实现
Java
/**
* 抽象形状类
*
*/
public abstract class Shape {
public int x;
public int y;
public String color;
public Shape() {
}
public Shape(Shape target) {
if (target != null) {
this.x = target.x;
this.y = target.y;
this.color = target.color;
}
}
public abstract Shape clone();
@Override
public boolean equals(Object object2) {
if (!(object2 instanceof Shape)) return false;
Shape shape2 = (Shape) object2;
return shape2.x == x && shape2.y == y && Objects.equals(shape2.color, color);
}
}
/**
* 圆形类
*
*/
public class Circle extends Shape {
public int radius;
public Circle() {
}
public Circle(Circle target) {
super(target);
if (target != null) {
this.radius = target.radius;
}
}
@Override
public Shape clone() {
return new Circle(this);
}
@Override
public boolean equals(Object object2) {
if (!(object2 instanceof Circle) || !super.equals(object2)) return false;
Circle shape2 = (Circle) object2;
return shape2.radius == radius;
}
}
/**
* 客户端
*
*/
public class Client {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
List<Shape> copies = new ArrayList<>();
Circle circle = new Circle();
circle.x = 10;
circle.y = 20;
circle.radius = 15;
circle.color = "red";
shapes.add(circle);
Circle anotherCircle = (Circle) circle.clone();
shapes.add(anotherCircle);
cloneAndCompare(shapes, copies);
}
private static void cloneAndCompare(List<Shape> shapes, List<Shape> copies) {
for (Shape shape : shapes) {
copies.add(shape.clone());
}
for (int i = 0; i < shapes.size(); i++) {
if (shapes.get(i) != copies.get(i)) {
System.out.println(i + ": 不同对象的形状");
if (shapes.get(i).equals(copies.get(i))) {
System.out.println(i + ": 它们完全相同");
} else {
System.out.println(i + ": 它们并不完全相同");
}
} else {
System.out.println(i + ": 形状对象相同");
}
}
}
}
Go
package main
import "fmt"
/**
* Node原型接口
*
*/
type Inode interface {
print(string)
clone() Inode
}
/**
* File具体原型
*
*/
type File struct {
name string
}
func (f *File) print(indentation string) {
fmt.Println(indentation + f.name)
}
func (f *File) clone() Inode {
return &File{name: f.name + "_clone"}
}
/**
* Folder具体原型
*
*/
type Folder struct {
children []Inode
name string
}
func (f *Folder) print(indentation string) {
fmt.Println(indentation + f.name)
for _, i := range f.children {
i.print(indentation + indentation)
}
}
func (f *Folder) clone() Inode {
cloneFolder := &Folder{name: f.name + "_clone"}
var tempChildren []Inode
for _, i := range f.children {
copy := i.clone()
tempChildren = append(tempChildren, copy)
}
cloneFolder.children = tempChildren
return cloneFolder
}
/**
* 客户端
*
*/
func main() {
file1 := &File{name: "File1"}
file2 := &File{name: "File2"}
file3 := &File{name: "File3"}
folder1 := &Folder{
children: []Inode{file1},
name: "Folder1",
}
folder2 := &Folder{
children: []Inode{folder1, file2, file3},
name: "Folder2",
}
fmt.Println("\n打印文件夹2大的继承结构")
folder2.print(" ")
cloneFolder := folder2.clone()
fmt.Println("\n打印克隆文件夹1的继承结构")
cloneFolder.print(" ")
}
适用场景
当希望复制对象但又不想依赖于这些对象所属的类,或者无法知道它们的私有属性时就可以用原型模式。
如果子类之间的区别仅仅是其对象的初始化方式,可以用原型模式来减少子类的数量。
优缺点
原型模式的优点。
可以获得对象而无需与其所属的类耦合。
可以通过继承以外的方式来获得复杂对象。
原型模式的缺点。
对象必须实现克隆接口。
如果对象有循环引用处理起来比较麻烦。
相关性
当不需要链接其他外部资源,存储的对象状态比较简单时,
原型模式
可以作为一个简化版本的备忘录模式
。原型模式
可用于保存命令模式
的历史记录。抽象工厂模式
通常基于一组工厂方法模式
,但也可以使用原型模式
来生成这些类的方法。工厂方法模式
可以演化为抽象工厂模式
、原型模式
和构建器
模式。可以通过
原型模式
来控制组合模式
和修饰器模式
的复杂结构。抽象工厂模式
、构建器模式
和原型模式
都可以用单例模式
来实现。
感谢支持
更多内容,请移步《超级个体》。