目录
原型模式
原型模式(Prototype Pattern)是⽤于创建重复的对象,同时⼜能保证性能。这种类型的设计模式属于创建型模式,它提供了⼀种创建对象的最佳⽅式。
这种模式是实现了⼀个原型接⼝,该接⼝⽤于创建当前对象的克隆。当直接创建对象的代价⽐较⼤时,则采⽤这种模式。例如,⼀个对象需要在⼀个⾼代价的数据库操作之后被创建。我们可以缓存该对象,在下⼀个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调⽤。
1 介绍
意图:⽤原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
主要解决:在运⾏期建⽴和删除原型。
何时使用:
1.当⼀个系统应该独⽴于它的产品创建,构成和表示时。
2.当要实例化的类是在运行时刻指定时,例如,通过动态装载。
3.为了避免创建⼀个与产品类层次平⾏的⼯⼚类层次时。
4.当⼀个类的实例只能有⼏个不同状态组合中的⼀种时。建⽴相应数⽬的原型并克隆它们可能⽐每次⽤合适的状态⼿⼯实例化该类更⽅便⼀些。
如何解决:利⽤已有的⼀个原型对象,快速地⽣成和原型对象⼀样的实例。
关键代码:
1.实现克隆操作,在Java中实现Cloneable接⼝,重写clone()⽅法;在.NET中可以使⽤Object类的 MemberwiseClone()⽅法来实现对象的浅拷⻉或通过序列化的⽅式来实现深拷⻉。
2.原型模式同样⽤于隔离类对象的使⽤者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接⼝。
应用实例:
1.细胞分裂。
2.Java中的Object clone()⽅法。
优点:
1.性能提⾼。
2.逃避构造⽅法的约束。
缺点: 1.配备克隆⽅法需要对类的功能进⾏通盘考虑,这对于全新的类不是很难,但对于已有的类不⼀定很容易,特别当 ⼀个类引⽤不⽀持串⾏化的间接对象,或者引⽤含有循环结构的时候。
2.必须实现Cloneable接⼝。
使⽤场景:
1.资源优化场景。
2.类初始化需要消耗非常多的资源,这个资源包括数据、硬件资源等。
3.性能和安全要求的场景。
4.通过new产⽣⼀个对象需要⾮常繁琐的数据准备或访问权限,则可以使⽤原型模式。
5.⼀个对象多个修改者的场景。
6.⼀个对象需要提供给其他对象访问,⽽且各个调⽤者可能都需要修改其值时,可以考虑使⽤原型模式拷⻉多个对象供调⽤者使⽤。
7.在实际项⽬中,原型模式很少单独出现,⼀般是和⼯⼚⽅法模式⼀起出现,通过clone()⽅法创建⼀个对象,然后由⼯⼚⽅法提供给调⽤者。原型模式已经与Java融为浑然⼀体,⼤家可以随⼿拿来使⽤。
注意事项:与通过对⼀个类进⾏实例化来构造新对象不同的是,原型模式是通过拷⻉⼀个现有对象⽣成新对象的。 浅拷⻉实现Cloneable接⼝,重写clone()⽅法;深拷⻉是通过实现Serializable读取⼆进制流。
2 实现
我们将创建⼀个抽象类Shape和扩展了Shape类的实体类。下⼀步是定义类ShapeCache,该类把shape对象存储 在⼀个Hashtable中,并在请求的时候返回它们的克隆。 PrototypePatternDemo类使⽤ShapeCache类来获取Shape对象。
具体实现步骤
1.创建⼀个Java项⽬。
2.创建⼀个实现了Cloneable接⼝的抽象类Shape。
package com.设计模式.原型模式;
/**
* 图形类。
*
* Cloneable接口:
* 1。功能:表示可以通过克隆的技术,实现对象的快速创建
* 2。实现:直接对类的实现Cloneable接口
* 3。方法:编写一个方法clone()方法,用来表示具体的克隆操作
*/
public abstract class Shape implements Cloneable {
private String id;
// 类型需要在子类中确定(需要在子类中访问父类中的成员)
protected String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
/*
public void setType(String type) {
this.type = type;
}
*/
abstract void draw();
public Object clone() {
Object clone = null;
try {
// 可以依据当前类的模板自动克隆一个一摸一样的对象
// Object类中有一个克隆方法
//父类是Object所有的类有一个共同的父类Object
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
3.创建扩展了Shape抽象类的圆形实体类Circle。
package com.设计模式.原型模式;
/**
* 圆型类
*/
public class Circle extends Shape {
public Circle() {
type = "圆型";
}
@Override
void draw() {
System.out.println("绘制一个圆形");
}
}
4.创建扩展了Shape抽象类的矩形实体类Rectangle。
package com.设计模式.原型模式;
/**
* 矩形类
*/
public class Rectangle extends Shape {
public Rectangle() {
type = "矩形";
}
@Override
void draw() {
System.out.println("绘制一个矩形");
}
}
5.创建扩展了Shape抽象类的正方形实体类Square。
package com.设计模式.原型模式;
/**
* 正方形类
*/
public class Square extends Shape {
public Square() {
type = "正方形";
}
@Override
void draw() {
System.out.println("绘制一个正方形");
}
}
6.创建⼀个ShapeCache类,从数据库获取实体类,并把它们存储在⼀个Hashtable中。
package com.设计模式.原型模式;
import java.util.Hashtable;
public class ShapeCache {
//创建一个对应的Hashtable的存储结构
private static Hashtable<String,Shape> shapeMap = new Hashtable<>();
//模拟在当前的存储Map中存放三个原始的对象
public static void load(){
Circle circle = new Circle();
circle.setId("1");
shapeMap.put(circle.getId(),circle);
Square square = new Square();
square.setId("2");
shapeMap.put(square.getId(),square);
Rectangle rectangle = new Rectangle();
rectangle.setId("3");
shapeMap.put(rectangle.getId(),rectangle);
}
//调用者根据Id来指定想要获取的对象
//克隆对象需要调用对象的clone方法来完成(向上转型)
public static Shape getShape(String shapeId){
Shape shape = shapeMap.get(shapeId);//根据用户传递的Id值来获取对象
return (Shape) shape.clone();
}
}
7.PrototypePatternDemo类使⽤ShapeCache类来获取存储在Hashtable中的形状的克隆。
package com.设计模式.原型模式;
public class ProtoTypePattern {
public static void main(String[] args) {
//加载初始的原始对象
ShapeCache.load();
Shape cloneCircle = ShapeCache.getShape("1");
System.out.println(cloneCircle.getType());
}
}
8.执⾏程序,输出结果。