一、原型模式 vs. 传统的复制对象
- 第一次看到原型模式这个名字时,我是懵逼的。这是啥意思啊?
- 看了相关介绍后,我更懵逼了,这原型模式不就是复制对象吗?这也能算一种设计模式?
1、传统的复制对象
- 传统的复制对象:必须new一个属于相同类的对象。 然后,必须遍历原始对象的所有成员变量, 并将成员变量值复制到新对象中。
public class User {
@Getter
@Setter
private String name;
@Setter
private String ak;
@Setter
@Getter
private String sk;
}
public class UserService {
public void doProcess(User user) {
User copyedUser = new User();
copyedUser.setName(user.getName());
copyedUser.setSk(user.getSk());
}
}
- 这里有个
小问题
: 有些对象可能拥有私有成员变量, 它们在对象本身以外是不可见的(如User的ak字段
)。 - 传统的复制还有
另外一个问题
。 必须知道对象所属的类才能创建复制品, 所以代码必须依赖该类。 - 还可能有
另外一个问题
: 有时只知道对象所实现的接口, 而不知道其所属的具体类, 比如向方法的某个参数传入实现了某个接口的任何对象。
public void execute(IBuy user) {
}
2、原型模式
2.1 原型模式是什么?
- 原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。(低耦合)
2.2 如何实现呢?(原型模式的思想)
- 原型模式将克隆过程委派给被克隆的实际对象(
让传入的对象
自身具有克隆能力,调用该对象的克隆(clone
)方法,即可完成克隆)。
- 在clone方法中,(1)由于知道自己所属的类,自然可以轻轻松松new一个当前类的对象。(2)由于类中的方法也能访问自己的私有成员变量,因此,可以毫无阻力的将原始对象所有的成员变量值复制到新建对象中。【原型模式解决了传统复制对象的3个问题】
2.3 对原型的理解
- 原型并不是计算机的独有概念,而是生活中的常见概念。当一个产品原型被验证是成功的,后续会被大量复制,并被销售到全国。因此,原型的本质就是被复制。
2.4 示例
2.4.1 示例1:Java 的 Cloneable (可克隆) 接口就是立即可用的原型模式
@ToString
public class User implements Cloneable {
@Getter
@Setter
private String name;
@Setter
private String ak;
@Setter
@Getter
private String sk;
@Override
public User clone() {
try {
return (User) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
public class Application {
public static void main(String[] args) {
User user = new User();
user.setName("张三");
user.setAk("123456");
user.setSk("654321");
User clonedUser = user.clone();
System.out.println(clonedUser);
}
}
- Cloneable仅仅是一个用于标识的接口,里面啥都没有。
public interface Cloneable {
}
protected native Object clone() throws CloneNotSupportedException;
- 一个类想用Object的clone()方法,那么就必须实现Cloneable接口,否则会抛异常:CloneNotSupportedException。
2.4.2 示例2:克隆时,用户没传入具体的类
public abstract class Shape implements Cloneable {
@Override
public Shape clone() throws CloneNotSupportedException {
return (Shape) super.clone();
}
}
@Data
public class Circle extends Shape {
private int radius;
}
@Data
public class Rectangle extends Shape {
private int width;
private int height;
}
public class Application {
public static void main(String[] args) {
Circle circle = new Circle();
circle.setRadius(10);
Rectangle rectangle = new Rectangle();
rectangle.setHeight(15);
rectangle.setWidth(5);
List<Shape> shapes = new ArrayList<>();
shapes.add(circle);
shapes.add(rectangle);
shapes.stream().forEach(shape -> {
try {
Shape clonedShape = shape.clone();
System.out.println(clonedShape);
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
});
}
}
- 即使没传入具体的类(Shape是抽象类),也能完成克隆。