java 设计模式-原型模式
1. 由来
原型模式是一种创建型设计模式,它的目标是通过克隆现有对象来创建新对象,而无需依赖于显式的实例化过程。该模式由于其类似复制粘贴的方式,因此被称为原型模式。
2. 官方常见五种示例命令和说明
以下是Java中原型模式的常见示例命令和说明:
java.lang.Cloneable
:这是一个接口,实现该接口的类可以被克隆。在使用原型模式时,需要确保被克隆的类实现了Cloneable
接口。java.lang.Object.clone()
:这是Object类的一个方法,用于创建并返回当前对象的副本。在使用原型模式时,可以重写该方法以实现对象的克隆。java.util.Cloneable
:这是一个标记接口,用于标识某个类可以被克隆。与java.lang.Cloneable
不同的是,该接口没有定义任何方法。java.io.Serializable
:这是一个接口,实现该接口的类可以通过序列化和反序列化来创建对象的副本。在使用原型模式时,可以通过将对象写入字节流,再从字节流中读取对象来实现克隆。java.io.ObjectOutputStream
和java.io.ObjectInputStream
:这两个类分别用于将对象写入字节流和从字节流中读取对象。通过使用这两个类,可以实现对象的序列化和反序列化,进而实现原型模式。
下面分别以浅拷贝和深拷贝为例,展示原型模式的代码演示:
浅拷贝示例:
class Rectangle implements Cloneable {
private int width;
private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
public class ShallowCloneExample {
public static void main(String[] args) throws CloneNotSupportedException {
Rectangle originalRectangle = new Rectangle(10, 20);
// 浅拷贝
Rectangle clonedRectangle = (Rectangle) originalRectangle.clone();
// 修改克隆对象的属性
clonedRectangle.setWidth(30);
clonedRectangle.setHeight(40);
System.out.println("Original rectangle: " + originalRectangle.getWidth() + " x " + originalRectangle.getHeight());
System.out.println("Cloned rectangle: " + clonedRectangle.getWidth() + " x " + clonedRectangle.getHeight());
}
}
输出结果为:
Original rectangle: 10 x 20
Cloned rectangle: 30 x 40
在上述示例中,我们定义了一个Rectangle
类,该类实现了Cloneable
接口并重写了clone()
方法,以实现浅拷贝。然后,我们创建了一个原始对象originalRectangle
,并对其进行浅拷贝得到clonedRectangle
对象。接着,我们修改了clonedRectangle
对象的宽度和高度属性,并打印出原始对象和克隆对象的属性值。
深拷贝示例:
class Address implements Cloneable {
private String city;
private String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void setCity(String city) {
this.city = city;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public String getStreet() {
return street;
}
}
class Person implements Cloneable {
private String name;
private Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// 深拷贝
Person clonedPerson = (Person) super.clone();
clonedPerson.address = (Address) address.clone();
return clonedPerson;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public Address getAddress() {
return address;
}
}
public class DeepCloneExample {
public static void main(String[] args) throws CloneNotSupportedException {
Address originalAddress = new Address("City1", "Street1");
Person originalPerson = new Person("John", originalAddress);
// 深拷贝
Person clonedPerson = (Person) originalPerson.clone();
// 修改克隆对象的属性
clonedPerson.setName("Tom");
clonedPerson.getAddress().setCity("City2");
System.out.println("Original person: " + originalPerson.getName() + ", " + originalPerson.getAddress().getCity());
System.out.println("Cloned person: " + clonedPerson.getName() + ", " + clonedPerson.getAddress().getCity());
}
}
输出结果为:
Original person: John, City1
Cloned person: Tom, City2
在上述示例中,我们定义了一个Address
类和一个Person
类,Person
类包含了一个Address
对象作为属性。两个类都实现了Cloneable
接口并重写了clone()
方法,以实现深拷贝。
我们首先创建了一个原始对象originalPerson
,并对其进行深拷贝得到clonedPerson
对象。然后,我们修改了clonedPerson
对象的名字和地址属性,并打印出原始对象和克隆对象的属性值。
可以看到,通过深拷贝,修改克隆对象的属性不会影响原始对象的属性。
3. 多种主要用法
原型模式的主要用途包括:
- 避免重复初始化:当创建一个新对象需要进行复杂的初始化过程时,可以通过克隆已有对象来避免重复执行初始化代码,提高性能和效率。
import java.util.ArrayList;
import java.util.List;
// 抽象原型类
abstract class Product implements Cloneable {
protected List<String> parts;
public Product() {
parts = new ArrayList<>();
}
public abstract void addPart(String part);
public abstract void showParts();
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 具体原型类:ProductA
class ProductA extends Product {
@Override
public void addPart(String part) {
parts.add(part);
}
@Override
public void showParts() {
System.out.println("Product A Parts:");
for (String part : parts) {
System.out.println("- " + part);
}
}
}
// 具体原型类:ProductB
class ProductB extends Product {
@Override
public void addPart(String part) {
parts.add(part);
}
@Override
public void showParts() {
System.out.println("Product B Parts:");
for (String part : parts) {
System.out.println("- " + part);
}
}
}
// 原型管理器
class ProductPrototypeManager {
private static ProductA productA;
private static ProductB productB;
static {
productA = new ProductA();
productA.addPart("Part A1");
productA.addPart("Part A2");
productB = new ProductB();
productB.addPart("Part B1");
productB.addPart("Part B2");
}
public static ProductA getProductA() throws CloneNotSupportedException {
return (ProductA) productA.clone();
}
public static ProductB getProductB() throws CloneNotSupportedException {
return (ProductB) productB.clone();
}
}
public class AvoidDuplicateInitializationExample {
public static void main(String[] args) throws CloneNotSupportedException {
ProductA productA1 = ProductPrototypeManager.getProductA();
productA1.addPart("Part A3");
ProductA productA2 = ProductPrototypeManager.getProductA();
productA1.showParts();
// Output:
// Product A Parts:
// - Part A1
// - Part A2
// - Part A3
productA2.showParts();
// Output:
// Product A Parts:
// - Part A1
// - Part A2
ProductB productB1 = ProductPrototypeManager.getProductB();
productB1.addPart("Part B3");
ProductB productB2 = ProductPrototypeManager.getProductB();
productB1.showParts();
// Output:
// Product B Parts:
// - Part B1
// - Part B2
// - Part B3
productB2.showParts();
// Output:
// Product B Parts:
// - Part B1
// - Part B2
}
}
在上述示例中,我们定义了一个抽象原型类Product
,并派生出两个具体原型类ProductA
和ProductB
。每个具体原型类都有一个parts
列表用于存储零件。
我们创建了一个原型管理器ProductPrototypeManager
,其中包含两个预先初始化的原型对象:productA
和productB
。通过调用getProductA
和getProductB
方法,可以获取它们的克隆副本。
在主程序中,我们首先获取ProductA
的克隆对象productA1
,并在其基础上添加了一个新的零件。然后,我们获取另一个ProductA
的克隆对象productA2
。
同样地,我们也获取了ProductB
的克隆对象productB1
并进行修改,然后再次获取另一个ProductB
的克隆对象productB2
。
通过使用原型模式,我们可以避免重复执行复杂的初始化过程。我们只需克隆已有对象,并在其基础上进行简单的修改即可快速创建新对象。这样可以提高性能和效率,同时保持代码的可读性和可维护性。
- 保护对象状态:通过克隆对象,可以在不影响原始对象的情况下对副本进行修改,从而保护了原始对象的状态。
在快速原型开发中,可以使用原型模式来快速构建和测试原型,以加快开发速度。如果某个对象需要在不同的场景中使用,并且每个场景需要稍有不同的配置或状态,那么可以使用原型模式来创建多个对象,并针对不同的场景进行定制。以下是一个示例:
import java.util.ArrayList;
import java.util.List;
// 抽象原型类
abstract class Product implements Cloneable {
protected String name;
protected double price;
protected List<String> attributes;
public Product() {
attributes = new ArrayList<>();
}
public abstract void setName(String name);
public abstract void setPrice(double price);
public abstract void addAttribute(String attribute);
public abstract void showInfo();
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 具体原型类
class ConcreteProduct extends Product {
public ConcreteProduct() {
super();
}
public void setName(String name) {
this.name = name;
}
public void setPrice(double price) {
this.price = price;
}
public void addAttribute(String attribute) {
attributes.add(attribute);
}
public void showInfo() {
System.out.println("Product Name: " + name);
System.out.println("Price: $" + price);
System.out.println("Attributes:");
for (String attribute : attributes) {
System.out.println("- " + attribute);
}
}
}
public class RapidPrototypeDevelopmentExample {
public static void main(String[] args) throws CloneNotSupportedException {
ConcreteProduct productPrototype = new ConcreteProduct();
productPrototype.setName("Prototype Product");
productPrototype.setPrice(10.0);
productPrototype.addAttribute("Attribute 1");
ConcreteProduct product1 = (ConcreteProduct) productPrototype.clone();
product1.addAttribute("Attribute 2");
ConcreteProduct product2 = (ConcreteProduct) productPrototype.clone();
product2.setName("Customized Product");
product2.setPrice(20.0);
product2.addAttribute("Attribute 3");
productPrototype.showInfo();
// Output:
// Product Name: Prototype Product
// Price: $10.0
// Attributes:
// - Attribute 1
product1.showInfo();
// Output:
// Product Name: Prototype Product
// Price: $10.0
// Attributes:
// - Attribute 1
// - Attribute 2
product2.showInfo();
// Output:
// Product Name: Customized Product
// Price: $20.0
// Attributes:
// - Attribute 1
// - Attribute 3
}
}
在上述示例中,我们定义了一个抽象原型类Product
,并派生出具体原型类ConcreteProduct
。每个具体原型类都有名称、价格和属性列表等属性。
我们首先创建了一个原型对象productPrototype
,并设置了其名称、价格和一个属性。然后,我们使用原型对象进行克隆,并对克隆对象进行修改,以定制不同的属性。
通过使用原型模式,我们可以快速创建多个对象,并针对不同的场景进行定制。在开发过程中,我们可以根据需要进行原型对象的复制和修改,从而加快开发速度,提高效率。这样可以避免从头开始构建对象,节省时间和精力。
- 动态创建对象:通过原型模式,可以在运行时动态地创建新对象,而无需事先知道具体的类名。
动态创建对象是原型模式的一个重要用途,它允许在运行时根据原型对象进行克隆操作,从而实现动态创建新对象的能力。以下是一个示例:
import java.util.HashMap;
import java.util.Map;
// 抽象原型类
abstract class Shape implements Cloneable {
protected String type;
public abstract void draw();
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 具体原型类:Circle
class Circle extends Shape {
public Circle() {
type = "Circle";
}
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
// 具体原型类:Rectangle
class Rectangle extends Shape {
public Rectangle() {
type = "Rectangle";
}
@Override
public void draw() {
System.out.println("Drawing a rectangle");
}
}
// 原型管理器
class ShapePrototypeManager {
private static Map<String, Shape> shapeMap = new HashMap<>();
static {
shapeMap.put("Circle", new Circle());
shapeMap.put("Rectangle", new Rectangle());
}
public static Shape getShape(String type) throws CloneNotSupportedException {
Shape shape = shapeMap.get(type);
if (shape != null) {
return (Shape) shape.clone();
}
return null;
}
}
public class DynamicObjectCreationExample {
public static void main(String[] args) throws CloneNotSupportedException {
Shape circle1 = ShapePrototypeManager.getShape("Circle");
if (circle1 != null) {
circle1.draw(); // Drawing a circle
}
Shape rectangle1 = ShapePrototypeManager.getShape("Rectangle");
if (rectangle1 != null) {
rectangle1.draw(); // Drawing a rectangle
}
Shape circle2 = ShapePrototypeManager.getShape("Circle");
if (circle2 != null) {
circle2.draw(); // Drawing a circle
}
}
}
在上述示例中,我们定义了一个抽象原型类Shape
,并派生出两个具体原型类Circle
和Rectangle
。然后,我们创建了一个原型管理器ShapePrototypeManager
,其中包含一个用于存储不同类型原型对象的shapeMap
。
在ShapePrototypeManager
中,我们通过getShape
方法获取指定类型的原型对象。如果存在该类型的原型对象,则对其进行克隆操作,并返回新创建的对象实例。
在主程序中,我们通过ShapePrototypeManager
动态地获取了两个圆形对象和一个矩形对象,并调用它们的draw
方法进行绘制。
通过原型模式,我们可以根据原型对象动态地创建新的对象实例,而无需在代码中显式指定具体的类名,从而实现了动态创建对象的能力。
- 实现快速原型开发:在原型模式中,可以通过复制现有的对象来快速构建和测试原型,从而加快开发速度。
在快速原型开发中,可以使用原型模式来快速构建和测试原型,以加快开发速度。如果某个对象需要在不同的场景中使用,并且每个场景需要稍有不同的配置或状态,那么可以使用原型模式来创建多个对象,并针对不同的场景进行定制。以下是一个示例:
假设我们正在开发一个电子商务平台,其中包含商品对象(Product)。商品对象有许多属性,如名称、价格、描述等。在不同的场景中,我们可能需要创建不同种类的商品对象,并为每个场景定制不同的属性。
首先,我们定义一个抽象原型类Product
,并实现它的具体原型类ConcreteProduct
。每个具体原型类都实现了clone()
方法,用于复制自身并返回一个新的克隆对象。
import java.util.ArrayList;
import java.util.List;
// 抽象原型类
abstract class Product implements Cloneable {
protected String name;
protected double price;
protected List<String> attributes;
public Product() {
attributes = new ArrayList<>();
}
public abstract void setName(String name);
public abstract void setPrice(double price);
public abstract void addAttribute(String attribute);
public abstract void showInfo();
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 具体原型类
class ConcreteProduct extends Product {
public ConcreteProduct() {
super();
}
public void setName(String name) {
this.name = name;
}
public void setPrice(double price) {
this.price = price;
}
public void addAttribute(String attribute) {
attributes.add(attribute);
}
public void showInfo() {
System.out.println("Product Name: " + name);
System.out.println("Price: $" + price);
System.out.println("Attributes:");
for (String attribute : attributes) {
System.out.println("- " + attribute);
}
}
}
public class RapidPrototypeDevelopmentExample {
public static void main(String[] args) throws CloneNotSupportedException {
ConcreteProduct productPrototype = new ConcreteProduct();
productPrototype.setName("Prototype Product");
productPrototype.setPrice(10.0);
productPrototype.addAttribute("Attribute 1");
ConcreteProduct product1 = (ConcreteProduct) productPrototype.clone();
product1.addAttribute("Attribute 2");
ConcreteProduct product2 = (ConcreteProduct) productPrototype.clone();
product2.setName("Customized Product");
product2.setPrice(20.0);
product2.addAttribute("Attribute 3");
productPrototype.showInfo();
// Output:
// Product Name: Prototype Product
// Price: $10.0
// Attributes:
// - Attribute 1
product1.showInfo();
// Output:
// Product Name: Prototype Product
// Price: $10.0
// Attributes:
// - Attribute 1
// - Attribute 2
product2.showInfo();
// Output:
// Product Name: Customized Product
// Price: $20.0
// Attributes:
// - Attribute 1
// - Attribute 3
}
}
在上述示例中,我们定义了一个抽象原型类Product
,并派生出具体原型类ConcreteProduct
。每个具体原型类都有名称、价格和属性列表等属性。
我们首先创建了一个原型对象productPrototype
,并设置了其名称、价格和一个属性。然后,我们使用原型对象进行克隆,并对克隆对象进行修改,以定制不同的属性。
通过使用原型模式,我们可以快速创建多个对象,并针对不同的场景进行定制。在开发过程中,我们可以根据需要进行原型对象的复制和修改,从而加快开发速度,提高效率。这样可以避免从头开始构建对象,节省时间和精力。
4. 有没有其他类似命令
除了上述提到的常见命令之外,Java中还有一些其他与原型模式相关的类和接口,例如:
-
java.util.Copyable
:这是一个标记接口,用于标识某个类可以被复制。与Cloneable
接口不同的是,Copyable
接口可以定义一些复制方法。 -
org.apache.commons.lang3.SerializationUtils
:这是Apache Commons Lang库中的一个工具类,提供了对对象进行序列化和反序列化的方法。
5. 区别
原型模式与其他创建型设计模式的区别在于它通过克隆现有对象来创建新对象,而不是通过显式的实例化过程或者通过工厂方法来创建。这使得原型模式更加灵活和高效,并且能够在运行时动态地创建对象。
与工厂模式相比,原型模式不需要创建具体的工厂类,而是直接由原型对象自身完成复制操作。这使得原型模式的实现更加简单,同时也减少了代码的耦合度。
6. 官方链接
请注意,以上链接可能会根据官方文档的更新发生变化。你可以通过搜索相关的关键词来找到最新的官方文档。