原型模式
原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。(这种不通过new关键字来产生一个对象,而是通过对象复制来实现的模式。)
原型模式结构
-
原型(Prototype)接口将对克隆方法进行声明。在绝大多数情况下,其中只会有一个名为
clone
克隆的方法。 -
具体原型(Concrete Prototype)类将实现克隆方法。除了将原始对象的数据复制到克隆体中之外,该方法有时还需处理克隆过程中的极端情况,例如克隆关联对象和梳理递归依赖等等。
-
客户端(Client)可以复制实现了原型接口的任何对象。
-
原型注册表
原型注册表提供了一种访问常用原型的简单方法,其中存储了一系列可供随时复制的预生成对象。
新建一个工厂类来实现注册表, 或者在原型基类中添加一个获取原型的静态方法。 该方法必须能够根据客户端代码设定的条件进行搜索。 搜索条件可以是简单的字符串, 或者是一组复杂的搜索参数。 找到合适的原型后, 注册表应对原型进行克隆, 并将复制生成的对象返回给客户端。
通用代码结构示例:
public class PrototypeClass implements Cloneable{
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try{
prototypeClass = (PrototypeClass)super.clone();
} catch (CloneNotSupportedException e){
//异常处理
}
return prototypeClass;
}
}
原型模式应用场景
-
如果你需要复制一些对象,同时又希望代码独立于这些对象所属的具体类,可以使用原型模式。
原型模式为客户端代码提供一个通用接口, 客户端代码可通过这一接口与所有实现了克隆的对象进行交互, 它也使得客户端代码与其所克隆的对象具体类独立开来。
-
如果子类的区别仅在于其对象的初始化方式, 那么你可以使用该模式来减少子类的数量。 别人创建这些子类的目的可能是为了创建特定类型的对象。
在原型模式中,你可以使用一系列预生成的、各种类型的对象作为原型。客户端不必根据需求对子类进行实例化,只需找到合适的原型并对其进行克隆即可。
**识别方法:**原型可以简单地通过
clone
或copy
等方法来识别。
原型模式优缺点
优点:
-
你可以克隆对象,而无需与它们所属的具体类相耦合。
-
你可以克隆预生成原型,避免反复运行初始化代码。
-
你可以更方便地生成复杂对象。
-
你可以用继承以外的方式来处理复杂对象的不同配置。
缺点
- 克隆包含循环引用的复杂对象可能会非常麻烦。
练手题目
题目描述
公司正在开发一个图形设计软件,其中有一个常用的图形元素是矩形。设计师在工作时可能需要频繁地创建相似的矩形,而这些矩形的基本属性是相同的(颜色、宽度、高度),为了提高设计师的工作效率,请你使用原型模式设计一个矩形对象的原型。使用该原型可以快速克隆生成新的矩形对象。
输入描述
首先输入一个字符串,表示矩形的基本属性信息,包括颜色、长度和宽度,用空格分隔,例如 “Red 10 5”。然后输入一个整数 N(1 ≤ N ≤ 100),表示使用原型创建的矩形数量。
输出描述
对于每个矩形,输出一行字符串表示矩形的详细信息,如 “Color: Red, Width: 10,Height: 5”。
提示信息
使用原型模式中的克隆方法实现矩形对象的创建。
题解:
原型模式解法:
import java.util.Scanner;
import java.io.*;
// 抽象类 Shape,表示形状的基类,原型模式
abstract class Shape{
protected int height ;
protected int width ;
protected String color ;
public Shape(){}
public Shape(int height,int width, String color){
this.height = height;
this.width = width;
this.color = color;
}
public abstract Shape clone();
//get、set方法
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
class Rectangle extends Shape{
public Rectangle(int height,int width, String color){
super(height, width, color);
}
@Override
public Shape clone(){
return new Rectangle(this.height, this.width, this.color);
}
}
public class Main{
public static void main (String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
String[] parts = input.split(" ");
if (parts.length == 3){
String color = parts[0];
int width ,height;
try{
width = Integer.parseInt(parts[1]);
height = Integer.parseInt(parts[2]);
Shape shape = new Rectangle(height,width ,color);
int num = scanner.nextInt();
for (int i=0 ;i<num;i++ ){
Shape clonedShape =shape.clone();
System.out.println("Color: "+color+", Width: "+width+", Height: "+ height);
}
}catch(NumberFormatException e){
System.out.println("输入错误,请重新输入");
}
} else {
System.out.println("输入格式错误,请按格式输入:颜色 宽度 高度");
}
scanner.close();
}
}
使用原型注册表来实现
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
// 原型模式抽象类Shape,表示形状的基类
abstract class Shape {
protected int height;
protected int width;
protected String color;
public Shape() {}
public Shape(int height, int width, String color) {
this.height = height;
this.width = width;
this.color = color;
}
// 抽象方法 clone,用于克隆形状
public abstract Shape clone();
//get、set方法。
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
// Rectangle 类,继承自 Shape 表示矩形
class Rectangle extends Shape {
public Rectangle(int height, int width, String color) {
super(height, width, color);
}
// 克隆方法,返回一个新的矩形对象
@Override
public Shape clone() {
return new Rectangle(this.height, this.width, this.color);
}
}
// 原型注册表类,用于存储和管理形状
class ShapeRegistry {
private Map<String, Shape> shapeMap = new HashMap<>();
// 注册形状,使用形状 ID 作为键
public void registerShape(String shapeId, Shape shape) {
shapeMap.put(shapeId, shape);
}
// 获取形状,通过克隆返回一个新的对象
public Shape getShape(String shapeId) {
Shape shape = shapeMap.get(shapeId);
return shape != null ? shape.clone() : null;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
ShapeRegistry shapeRegistry = new ShapeRegistry();
// 注册一个默认的矩形形状
shapeRegistry.registerShape("defaultRectangle", new Rectangle(10, 20, "red"));
String input = scanner.nextLine();
String[] parts = input.split(" ");
if (parts.length == 3) {
String color = parts[0];
try {
int width = Integer.parseInt(parts[1]);
int height = Integer.parseInt(parts[2]);
//创建并注册一个新的矩形
Shape newRectangle = new Rectangle(height, width, color);
shapeRegistry.registerShape("userRectangle", newRectangle);
int num = scanner.nextInt();
for (int i = 0; i < num; i++) {
Shape clonedShape = shapeRegistry.getShape("userRectangle");
if (clonedShape != null) {
System.out.println("Color: " + clonedShape.getColor() +
", Width: " + clonedShape.getWidth() +
", Height: " + clonedShape.getHeight());
} else {
System.out.println("在注册表中找不到形状.");
}
}
} catch (NumberFormatException e) {
System.out.println("输入错误,请重新输入.");
}
} else {
System.out.println("输入格式错误,请按格式输入:颜色 宽度 高度.");
}
scanner.close();
}
}