使用示例: Java 的 Cloneable
(可克隆) 接口就是立即可用的原型模式。
任何类都可通过实现该接口来实现可被克隆的性质。
java.lang.Object#clone()
(类必须实现 java.lang.Cloneable
接口)
识别方法: 原型可以简单地通过 clone
或 copy
等方法来识别。
01复制图形
让我们来看看在不使用标准 Cloneable
接口的情况下如何实现原型模式。
02shapes: 形状列表
shapes/Shape.java: 通用形状接口
package refactoring_guru.prototype.example.shapes; import java.util.Objects; 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); } }
shapes/Circle.java: 简单形状
package refactoring_guru.prototype.example.shapes; 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; } }
shapes/Rectangle.java: 另一个形状
package refactoring_guru.prototype.example.shapes; public class Rectangle extends Shape { public int width; public int height; public Rectangle() { } public Rectangle(Rectangle target) { super(target); if (target != null) { this.width = target.width; this.height = target.height; } }
@Override
public Shape clone() { return new Rectangle(this); } @Override public boolean equals(Object object2) { if (!(object2 instanceof Rectangle) || !super.equals(object2)) return false; Rectangle shape2 = (Rectangle) object2; return shape2.width == width && shape2.height == height; } }
Demo.java: 克隆示例
package refactoring_guru.prototype.example; import refactoring_guru.prototype.example.shapes.Circle; import refactoring_guru.prototype.example.shapes.Rectangle; import refactoring_guru.prototype.example.shapes.Shape; import java.util.ArrayList; import java.util.List; public class Demo { public static void main(String[] args) { List<Shape> shapes = new ArrayList<>(); List<Shape> shapesCopy = 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); Rectangle rectangle = new Rectangle(); rectangle.width = 10; rectangle.height = 20; rectangle.color = "blue"; shapes.add(rectangle); cloneAndCompare(shapes, shapesCopy); } private static void cloneAndCompare(List<Shape> shapes, List<Shape> shapesCopy) { for (Shape shape : shapes) { shapesCopy.add(shape.clone()); } for (int i = 0; i < shapes.size(); i++) { if (shapes.get(i) != shapesCopy.get(i)) { System.out.println(i + ": Shapes are different objects (yay!)"); if (shapes.get(i).equals(shapesCopy.get(i))) { System.out.println(i + ": And they are identical (yay!)"); } else { System.out.println(i + ": But they are not identical (booo!)"); } } else { System.out.println(i + ": Shape objects are the same (booo!)"); } } } }
OutputDemo.txt: 执行结果
0: Shapes are different objects (yay!)
0: And they are identical (yay!)
1: Shapes are different objects (yay!)
1: And they are identical (yay!)
2: Shapes are different objects (yay!)
2: And they are identical (yay!)
原型注册站
你可以实现中心化的原型注册站 (或工厂), 其中包含一系列预定义的原型对象。 这样一来, 你就可以通过传递对象名称或其他参数的方式从工厂处获得新的对象。 工厂将搜索合适的原型, 然后对其进行克隆复制, 最后将副本返回给你。
03cache
cache/BundledShapeCache.java: 原型工厂 package refactoring_guru.prototype.caching.cache; import refactoring_guru.prototype.example.shapes.Circle; import refactoring_guru.prototype.example.shapes.Rectangle; import refactoring_guru.prototype.example.shapes.Shape; import java.util.HashMap; import java.util.Map; public class BundledShapeCache { private Map<String, Shape> cache = new HashMap<>(); public BundledShapeCache() { Circle circle = new Circle(); circle.x = 5; circle.y = 7; circle.radius = 45; circle.color = "Green"; Rectangle rectangle = new Rectangle(); rectangle.x = 6; rectangle.y = 9; rectangle.width = 8; rectangle.height = 10; rectangle.color = "Blue"; cache.put("Big green circle", circle); cache.put("Medium blue rectangle", rectangle); } public Shape put(String key, Shape shape) { cache.put(key, shape); return shape; } public Shape get(String key) { return cache.get(key).clone(); } }
Demo.java: 克隆示例
package refactoring_guru.prototype.caching; import refactoring_guru.prototype.caching.cache.BundledShapeCache; import refactoring_guru.prototype.example.shapes.Shape; public class Demo { public static void main(String[] args) { BundledShapeCache cache = new BundledShapeCache(); Shape shape1 = cache.get("Big green circle"); Shape shape2 = cache.get("Medium blue rectangle"); Shape shape3 = cache.get("Medium blue rectangle"); if (shape1 != shape2 && !shape1.equals(shape2)) { System.out.println("Big green circle != Medium blue rectangle (yay!)"); } else { System.out.println("Big green circle == Medium blue rectangle (booo!)"); } if (shape2 != shape3) { System.out.println("Medium blue rectangles are two different objects (yay!)"); if (shape2.equals(shape3)) { System.out.println("And they are identical (yay!)"); } else { System.out.println("But they are not identical (booo!)"); } } else { System.out.println("Rectangle objects are the same (booo!)"); } } }
OutputDemo.txt: 执行结果
Big green circle != Medium blue rectangle (yay!) Medium blue rectangles are two different objects (yay!) And they are identical (yay!)