所有设计模式传送门
本文将一起介绍学习下设计模式之原型模式。
在某些情况下,可能不希望反复使用类的构造方法创建许多对象,而是希望用该类创建一个对象后,以该类为原型得到该对象的若干个复制品。也就是说,将一个对象定义为原型对象,要求改原型对象提供一个方法使该原型对象调用此方法可以复制一个和自己有完全相同状态的同类型对象。
当对象调用Object类中的clone()方法时,JVM将会逐个复制该对象的成员变量然后创建一个新的对象返回,所以JVM要求调用clone()方法的对象必须实现Cloneable()接口。Cloneable接口没有任何方法,该接口的唯一作用就是让JVM知道实现该接口使可以被克隆的。
原型模式包含两种角色:
1、抽象原型(Prototype): 接口,负责定义对象复制自身的方法。
2、具体原型(Concrete Prototype): 实现该原型接口的类。具体原型实现抽象原型中的方法,以便所创建的对象调用该方法复制自己。
优点:
1、当创建类的新实例的代价更大时,使用原型模式复制一个已有的实例可以提高创建新实例的效率
2、可以动态的保存当前对象的状态,在运行时可以随时使用对象流保存当前对象的一个复制品
3、可以在运行时,创建一个新的对象,而无须创建一系列类和继承结构
4、可以动态地添加、删除原型的复制品
简单的例子1:
public class Circle implements Cloneable{
private double radius;
public double getRadius() {
return radius;
}
public void setRadius(double r) {
this.radius = r;
}
//重写clone方法
protected Object clone() throws CloneNotSupportedException {
Object object = super.clone();
return object;
}
}
public class Example {
public static void main(String[] args) {
Circle circle = new Circle();
circle.setRadius(198.99);
try {
Circle circleCopy = (Circle) circle.clone(); //调用clone复制自己
System.out.println("circle对象中的数据:"+circle.getRadius());
System.out.println("circleCopy对象中的数据:"+circleCopy.getRadius());
} catch (CloneNotSupportedException e) {
System.out.println(e.toString());
}
}
}
运行结果:
简单的例子2:克隆容器
设计要求:在一个窗口中有一个容器,该容器中有若干个按钮组件,用户单击按钮可以为按钮选择一个背景颜色,当用户为所有按钮选定颜色后,希望复制当前容器,并把这个复制品特添加到当前窗口中。
/**
* 抽象原型接口类
*/
public interface CloneContainer {
public Object cloneContainer();
}
/**
* 具体原型类
*/
public class ButtonContainer extends JPanel implements CloneContainer,ActionListener{
private static final long serialVersionUID = -6785205881023177580L;
JButton[] button;
public ButtonContainer() {
button = new JButton[25];
setLayout(new GridLayout(5, 5));
for (int i = 0; i < 25; i++) {
button[i] = new JButton();
add(button[i]);
button[i].addActionListener(this);
}
}
public void actionPerformed(ActionEvent e) {
JButton b = (JButton) e.getSource();
Color newColor = JColorChooser.showDialog(null, "", b.getBackground());
if (newColor != null) {
b.setBackground(newColor);
}
}
//实现接口中的方法
public Object cloneContainer() {
Object object = null;
try {
ByteArrayOutputStream outOne = new ByteArrayOutputStream();
ObjectOutputStream outTwo = new ObjectOutputStream(outOne);
//将原型对象写入对象输出流
outTwo.writeObject(this);
ByteArrayInputStream inOne = new ByteArrayInputStream(outOne.toByteArray());
ObjectInputStream inTwo = new ObjectInputStream(inOne);
//创建新对象,原型的复制品
object = inTwo.readObject();
} catch (Exception e) {
System.out.println(e);
}
return object;
}
}
public class Application extends JFrame implements ActionListener{
private static final long serialVersionUID = 1L;
JTabbedPane jtp;
ButtonContainer con;
JButton add;
JButton del;
public Application() {
add = new JButton("复制窗口中的当前容器");
del = new JButton("删除窗口中的当前容器");
add.addActionListener(this);
del.addActionListener(this);
JPanel pSouth = new JPanel();
pSouth.add(add);
pSouth.add(del);
add(pSouth, BorderLayout.SOUTH);
con = new ButtonContainer();
jtp = new JTabbedPane(JTabbedPane.LEFT);
add(jtp, BorderLayout.CENTER);
jtp.add("原型容器", con);
setBounds(100,100,500,300);
setVisible(true);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == add) {
int index = jtp.getSelectedIndex();
ButtonContainer container = (ButtonContainer) jtp.getComponentAt(index);
ButtonContainer conCopy = (ButtonContainer) container.cloneContainer();
jtp.add("复制的容器",conCopy);
}
if (e.getSource() == del) {
int index = jtp.getSelectedIndex();
ButtonContainer container = (ButtonContainer) jtp.getComponentAt(index);
jtp.remove(index);
}
}
public static void main(String[] args) {
new Application();
}
}
运行结果:
参考书籍:《Java设计模式》