title: “理解工廠模式”
url: “https://wsk1103.github.io/”
tags:
- 設計模式
是什麼
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
創建型模式。在基類中定義一個創建對象的接口,並且讓子類選擇實例化哪個類。工廠方法允許類將實例化延遲到子類。
工廠模式的分類
- Factory Method,工廠方法模式。
- Abstract Factory,抽象工廠模式。
優缺點
優點:
解耦:把對象的創建和使用的過程分開。既只負責對象的創建,對象是怎麼使用的,就不關我的事了。
降低代碼的重複性:如果創建一個對象比較複雜,但是許多地方需要使用到對象,那麼就會有許多重複的代碼。
降低維護成本:由於工廠模式只負責對象的創建,所以當業務邏輯發生變化時,不需要修改所有創建該對象的類,只需要在創建的邏輯裏面修改即可。
工廠方法模式
在基類的編程中,工廠方法模式是一種創建型模式,它使用工廠方法來處理創建對象的問題,而無需指定確切的類。這是通過調用工廠方法創建對象來完成的,也就是在接口中指定並由子類實現,或者在基類中實現並由子類覆蓋,而不是通過調用構造函數。
例子
鐵匠鑄造兵器,精靈需要精靈類的兵器,並且獸人也需要獸人類的兵器。根據相應的種族選擇相應的鐵匠來鑄造兵器。
//鐵匠
public interface Blacksmith {
Weapon manufactureWeapon(WeaponType weaponType);
}
//兵器
public interface Weapon {
}
//精靈兵器
public class ElfWeapon implements Weapon{
}
//獸人兵器
public class OrcWeapon implements Weapon{
}
//製作精靈兵器的鐵匠
public class ElfBlacksmith implements Blacksmith {
public Weapon manufactureWeapon(WeaponType weaponType) {
return new ElfWeapon(weaponType);
}
}
//製作獸人兵器的鐵匠
public class OrcBlacksmith implements Blacksmith {
public Weapon manufactureWeapon(WeaponType weaponType) {
return new OrcWeapon(weaponType);
}
}
現在根據需要選擇相應的鐵匠
//精靈
Blacksmith blacksmith = new ElfBlacksmith();
//兵器-槍
blacksmith.manufactureWeapon(WeaponType.SPEAR);
//兵器-盾
blacksmith.manufactureWeapon(WeaponType.SHIELD);
//獸人同理
應用
- 一個類不知道它所需要的對象的類,在工廠模式中,客戶端不需要知道具體產品類的類名,只需要知道對應的工廠即可,具體的產品對象由具體的工廠創建,但是客戶端需要知道創建具體產品是哪個工廠類。
- 一個類通過其子類來指定創建哪個對象,在工廠模式中,對於抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建哪個對象。
- 將創建的對象委託給多個工廠子類的某一個,客戶端在使用時,不需要關心是哪一個工廠子類在創建產品子類,需要時動態指定,可以將具體的工廠類的類名存儲在配置文件或者數據庫中。
工廠方法模式角色分配
- 抽象工廠角色:是工廠模式的核心,與應用程序無關。任何在模式中創建的對象的工廠類必須實現該接口。
- 具體工廠角色:抽象工廠類的具體實現,包含着與應用程序相關的邏輯。
- 抽象產品角色:產品對象的共同父類或共同擁有的接口。
- 具體產品對象:實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠創建,它們之間往往一一對應
java中的應用
- java.util.Calendar
- java.util.ResourceBundle
- java.text.NumberFormat
- java.nio.charset.Charset
- java.net.URLStreamHandlerFactory
- java.util.EnumSet
- javax.xml.bind.JAXBContext
抽象工廠模式
提供用於創建相關或從屬對象族的接口,而無需指定其具體類。
抽象工廠模式是工廠方法模式的進一步深化,在抽象工廠模式中,工廠類不僅可以創建一種產品,還能創建一組產品。
例子
現在有一組產品:城堡,國王,軍隊。
現在有2個國家:精靈和獸人。
//城堡
public interface Castle {
String getDescription();
}
//國王
public interface King {
String getDescription();
}
//軍隊
public interface Army {
String getDescription();
}
//精靈的實現
// Elven implementations ->
public class ElfCastle implements Castle {
static final String DESCRIPTION = "This is the Elven castle!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class ElfKing implements King {
static final String DESCRIPTION = "This is the Elven king!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class ElfArmy implements Army {
static final String DESCRIPTION = "This is the Elven Army!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
//獸人的實現同理
// Orcish implementations similarly...
接下來精靈和獸人王國將要包含城堡,國王,軍隊。
//王國工廠
public interface KingdomFactory {
Castle createCastle();
King createKing();
Army createArmy();
}
//精靈王國
public class ElfKingdomFactory implements KingdomFactory {
public Castle createCastle() {
return new ElfCastle();
}
public King createKing() {
return new ElfKing();
}
public Army createArmy() {
return new ElfArmy();
}
}
//獸人王國
public class OrcKingdomFactory implements KingdomFactory {
public Castle createCastle() {
return new OrcCastle();
}
public King createKing() {
return new OrcKing();
}
public Army createArmy() {
return new OrcArmy();
}
}
工廠有了,現在開始建造精靈王國
KingdomFactory factory = new ElfKingdomFactory();
Castle castle = factory.createCastle();
King king = factory.createKing();
Army army = factory.createArmy();
castle.getDescription(); // Output: This is the Elven castle!
king.getDescription(); // Output: This is the Elven king!
army.getDescription(); // Output: This is the Elven Army!
此外,我們還可以設計不同的工廠來實現不同的具體工廠。
通過枚舉和switch來區分具體工廠實現。
public static class FactoryMaker {
public enum KingdomType {
ELF, ORC
}
public static KingdomFactory makeFactory(KingdomType type) {
switch (type) {
case ELF:
return new ElfKingdomFactory();
case ORC:
return new OrcKingdomFactory();
default:
throw new IllegalArgumentException("KingdomType not supported.");
}
}
}
public static void main(String[] args) {
App app = new App();
LOGGER.info("Elf Kingdom");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
LOGGER.info(app.getArmy().getDescription());
LOGGER.info(app.getCastle().getDescription());
LOGGER.info(app.getKing().getDescription());
LOGGER.info("Orc Kingdom");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
-- similar use of the orc factory
}
應用
- 和工廠方法一樣客戶端不需要知道它所創建的對象的類
- 需要一組對象共同完成某種功能時,並且可能存在多組對象完成不同功能的情況。(同屬於同一個產品族的產品)
- 系統結構穩定,不會頻繁的增加對象。(因爲一旦增加就需要修改原有代碼,不符合開閉原則)
工廠方法模式角色分配
- 抽象工廠角色:是工廠模式的核心,與應用程序無關。任何在模式中創建的對象的工廠類必須實現該接口。
- 具體工廠角色:抽象工廠類的具體實現,包含着與應用程序相關的邏輯。
- 抽象產品角色:產品對象的共同父類或共同擁有的接口。
- 具體產品對象:實現了抽象產品角色所定義的接口。在抽象工廠中創建的產品屬於同一產品族,這不同於工廠模式中的工廠只創建單一產品。
java中的應用
javax.xml.parsers.DocumentBuilderFactory
javax.xml.transform.TransformerFactory
javax.xml.xpath.XPathFactory