原型模式
此模式難度系數(shù)為初級潜的,由Gang Of Four提出骚揍。
原型模式是用于創(chuàng)建重復的對象,提高性能啰挪。這種模式實現(xiàn)了一個原型接口信不,該接口用于創(chuàng)建當前對象的克隆。當直接創(chuàng)建對象的代價比較大時亡呵,則采用這種模式抽活。
例如一個對象需要在一個高代價的數(shù)據(jù)庫操作或者遠程連接之后被創(chuàng)建,我們可以緩存該對象锰什,在下一個請求時返回它的克隆下硕,在需要的時候更新數(shù)據(jù)庫或者通知遠程連接,以此來減少數(shù)據(jù)庫或遠程連接的調(diào)用汁胆。
意圖
用原型實例指定創(chuàng)建對象的種類梭姓,并且通過拷貝這些原型創(chuàng)建新的對象。
主要解決:在運行期建立和刪除原型嫩码。
何時使用:
1誉尖、當一個系統(tǒng)應該獨立于它的產(chǎn)品創(chuàng)建,構成和表示時铸题。
2铡恕、當要實例化的類是在運行時刻指定時琢感,例如,通過動態(tài)裝載没咙。
3猩谊、為了避免創(chuàng)建一個與產(chǎn)品類層次平行的工廠類層次時千劈。
4祭刚、當一個類的實例只能有幾個不同狀態(tài)組合中的一種時。建立相應數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實例化該類更方便一些墙牌。
如何解決:利用已有的一個原型對象涡驮,快速地生成和原型對象一樣的實例。
關鍵代碼:
1喜滨、實現(xiàn)克隆操作捉捅,在 JAVA 中實現(xiàn) Cloneable接口,重寫 clone()方法虽风。在 .NET 中可以使用 Object 類的 MemberwiseClone() 方法來實現(xiàn)對象的淺拷貝或通過序列化的方式來實現(xiàn)深拷貝棒口。
2、原型模式同樣用于隔離類對象的使用者和具體類型(易變類)之間的耦合關系辜膝,它同樣要求這些"易變類"擁有穩(wěn)定的接口无牵。
解釋
現(xiàn)實世界的例子
記得多莉嗎?克隆的羊厂抖!讓我們不要談細節(jié)茎毁,這里的關鍵點全是克隆
簡而言之
通過克隆基于現(xiàn)有對象來創(chuàng)建新對象
維基百科
原型模式是軟件開發(fā)中一種創(chuàng)造性的設計模式。當要創(chuàng)建的對象類型由一個原型實例確定并使用時忱辅,該原型實例被克隆以產(chǎn)生新的對象七蜘。
簡而言之,它允許你創(chuàng)建一個現(xiàn)有對象的副本墙懂,并根據(jù)你的需要修改它橡卤,而不是從頭開始創(chuàng)建一個對象并設置它
程序示例
在Java中,可以通過實現(xiàn)java.lang.Cloneable接口并重寫clone方法來輕易的做到克隆對象
class Sheep implements Cloneable {
private String name;
public Sheep(String name) { this.name = name; }
public void setName(String name) { this.name = name; }
public String getName() { return name; }
@Override
public Sheep clone() throws CloneNotSupportedException {
return new Sheep(name);
}
}
然后上面這個Sheep類對象可以被克隆如下:
Sheep original = new Sheep("Jolly");
System.out.println(original.getName()); // Jolly
// Clone and modify what is required
Sheep cloned = original.clone();
cloned.setName("Dolly");
System.out.println(cloned.getName()); // Dolly
應用場景
1损搬、資源優(yōu)化場景碧库。
2、類初始化需要消化非常多的資源场躯,這個資源包括數(shù)據(jù)谈为、硬件資源等。
3踢关、性能和安全要求的場景伞鲫。
4、通過 new 產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準備或訪問權限签舞,則可以使用原型模式秕脓。
5柒瓣、一個對象多個修改者的場景。
6吠架、一個對象需要提供給其他對象訪問芙贫,而且各個調(diào)用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調(diào)用者使用
Java中的現(xiàn)實例子
寫在最后
注意事項:與通過對一個類進行實例化來構造新對象不同的是傍药,原型模式是通過拷貝一個現(xiàn)有對象生成新對象的磺平。
淺拷貝實現(xiàn) Cloneable接口,重寫clone方法拐辽,深拷貝是通過實現(xiàn) Serializable接口 讀取二進制流來實現(xiàn)
在實際項目中拣挪,原型模式很少單獨出現(xiàn),一般是和工廠方法模式一起出現(xiàn)俱诸,通過 clone 的方法創(chuàng)建一個對象菠劝,然后由工廠方法提供給調(diào)用者。原型模式已經(jīng)與 Java 融為渾然一體睁搭,我們可以隨手拿來使用赶诊。
接下來我們就來編寫一個原型模式與工廠方法模式相結合的程序代碼示例。
我們有一個HeroFactory工廠园骆,這個工廠可以生產(chǎn)不同類型的(獸族舔痪、精靈族)Mage(魔法師)、Warlord(軍隊)遇伞、Beast(獸王)辙喂,只是這些類型的產(chǎn)物在工廠中都不是直接New出來的,而是采用原型模式通過已有類型對象clone出來的鸠珠。
首先我們畫出這個程序的UML類圖如下:
接下來根據(jù)類圖巍耗,步驟一:編寫Prototype抽象類
/**
*
* Prototype
*
*/
public abstract class Prototype implements Cloneable {
public abstract Object copy() throws CloneNotSupportedException;
}
步驟二:編寫繼承Prototype的Beast、Warlord渐排、Mage抽象類
/**
*
* Beast
*
*/
public abstract class Beast extends Prototype {
@Override
public abstract Beast copy() throws CloneNotSupportedException;
}
/**
*
* Mage
*
*/
public abstract class Mage extends Prototype {
@Override
public abstract Mage copy() throws CloneNotSupportedException;
}
/**
*
* Warlord
*
*/
public abstract class Warlord extends Prototype {
@Override
public abstract Warlord copy() throws CloneNotSupportedException;
}
步驟三:編寫精靈族和獸人族具體子類炬太,繼承步驟二定義的抽象類
public class ElfBeast extends Beast {
private String helpType;
public ElfBeast(String helpType) {
this.helpType = helpType;
}
public ElfBeast(ElfBeast elfBeast) {
this.helpType = elfBeast.helpType;
}
@Override
public Beast copy() throws CloneNotSupportedException {
return new ElfBeast(this);
}
@Override
public String toString() {
return "Elven eagle helps in " + helpType;
}
}
public class ElfMage extends Mage {
private String helpType;
public ElfMage(String helpType) {
this.helpType = helpType;
}
public ElfMage(ElfMage elfMage) {
this.helpType = elfMage.helpType;
}
@Override
public ElfMage copy() throws CloneNotSupportedException {
return new ElfMage(this);
}
@Override
public String toString() {
return "Elven mage helps in " + helpType;
}
}
/**
*
* ElfWarlord
*
*/
public class ElfWarlord extends Warlord {
private String helpType;
public ElfWarlord(String helpType) {
this.helpType = helpType;
}
public ElfWarlord(ElfWarlord elfWarlord) {
this.helpType = elfWarlord.helpType;
}
@Override
public ElfWarlord copy() throws CloneNotSupportedException {
return new ElfWarlord(this);
}
@Override
public String toString() {
return "Elven warlord helps in " + helpType;
}
}
public class OrcBeast extends Beast {
private String weapon;
public OrcBeast(String weapon) {
this.weapon = weapon;
}
public OrcBeast(OrcBeast orcBeast) {
this.weapon = orcBeast.weapon;
}
@Override
public Beast copy() throws CloneNotSupportedException {
return new OrcBeast(this);
}
@Override
public String toString() {
return "Orcish wolf attacks with " + weapon;
}
}
//剩下的獸人OrcMage、OrcWarlord與上面的Elf類似編寫即可...
步驟四:編寫HeroFactory接口和它的實現(xiàn)類:
/**
*
* Interface for the factory class.
*
*/
public interface HeroFactory {
Mage createMage();
Warlord createWarlord();
Beast createBeast();
}
/**
*
* Concrete factory class.
*
*/
public class HeroFactoryImpl implements HeroFactory {
private Mage mage;
private Warlord warlord;
private Beast beast;
/**
* Constructor
*/
public HeroFactoryImpl(Mage mage, Warlord warlord, Beast beast) {
this.mage = mage;
this.warlord = warlord;
this.beast = beast;
}
/**
* Create mage
*/
public Mage createMage() {
try {
return mage.copy();
} catch (CloneNotSupportedException e) {
return null;
}
}
/**
* Create warlord
*/
public Warlord createWarlord() {
try {
return warlord.copy();
} catch (CloneNotSupportedException e) {
return null;
}
}
/**
* Create beast
*/
public Beast createBeast() {
try {
return beast.copy();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
步驟五:編寫App客戶端類:
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Program entry point
*
* @param args command line args
*/
public static void main(String[] args) {
HeroFactory factory;
Mage mage;
Warlord warlord;
Beast beast;
factory = new HeroFactoryImpl(new ElfMage("cooking"), new ElfWarlord("cleaning"), new ElfBeast("protecting"));
mage = factory.createMage();
warlord = factory.createWarlord();
beast = factory.createBeast();
LOGGER.info(mage.toString());
LOGGER.info(warlord.toString());
LOGGER.info(beast.toString());
factory = new HeroFactoryImpl(new OrcMage("axe"), new OrcWarlord("sword"), new OrcBeast("laser"));
mage = factory.createMage();
warlord = factory.createWarlord();
beast = factory.createBeast();
LOGGER.info(mage.toString());
LOGGER.info(warlord.toString());
LOGGER.info(beast.toString());
}
}
最后運行App類驯耻,程序輸出如下:
17:04:21.430 [main] INFO com.iluwatar.prototype.App - Elven mage helps in cooking
17:04:21.433 [main] INFO com.iluwatar.prototype.App - Elven warlord helps in cleaning
17:04:21.434 [main] INFO com.iluwatar.prototype.App - Elven eagle helps in protecting
17:04:21.434 [main] INFO com.iluwatar.prototype.App - Orcish mage attacks with axe
17:04:21.434 [main] INFO com.iluwatar.prototype.App - Orcish warlord attacks with sword
17:04:21.434 [main] INFO com.iluwatar.prototype.App - Orcish wolf attacks with laser
原型模式中主要有三個登場角色:
1亲族、原型角色:定義用于復制現(xiàn)有實例來生成新實例的方法,上面的例子中Prototype類即是可缚。
2霎迫、具體原型角色:實現(xiàn)用于復制現(xiàn)有實例來生成新實例的方法,上面的例子中ElfBeast帘靡、ElfMage知给、ElfWarlord、Orc...等都是。
3涩赢、使用者角色:維護一個注冊表戈次,并提供一個找出正確實例原型的方法。最后筒扒,提供一個獲取新實例的方法怯邪,用來委托復制實例的方法生成新實例。上面的例子中HeroFactoryImpl即是花墩。
以上悬秉,原型模式我就在這里介紹完畢,至此設計模式中創(chuàng)建型模式我們已全部學習完畢观游。
大家可以試著去把工廠模式搂捧、抽象工廠模式、單例模式懂缕、建造者模式和今天學習的原型模式組合起來使用,每次組合1-2種設計模式來設計你的應用程序吧王凑,自主設計出來你肯定會有意想不到的收獲和體驗的搪柑。
下一篇文章我們將學習結構性模式中的適配器模式(Adapter Pattern)
碼字不易,各位看官如果喜歡的話索烹,請給點個喜歡??工碾,關注下我,我將努力持續(xù)不斷的更新