所有設計模式傳送門
本文將一起介紹學習下設計模式之原型模式。
在某些情況下,可能不希望反覆使用類的構造方法創建許多對象,而是希望用該類創建一個對象後,以該類爲原型得到該對象的若干個複製品。也就是說,將一個對象定義爲原型對象,要求改原型對象提供一個方法使該原型對象調用此方法可以複製一個和自己有完全相同狀態的同類型對象。
當對象調用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設計模式》