1. 工廠模式
1.1 概述
工廠模式(Factory Pattern)是一種創(chuàng)建型設(shè)計(jì)模式旁趟,提供了一種將對(duì)象創(chuàng)建的過(guò)程與對(duì)象的使用分離的機(jī)制昼激。它通過(guò)將實(shí)例化對(duì)象的邏輯封裝到一個(gè)工廠類(lèi)中,從而減少客戶(hù)端和具體類(lèi)的耦合锡搜。這使得代碼更加靈活和易于維護(hù)橙困,尤其是當(dāng)我們需要?jiǎng)?chuàng)建不同種類(lèi)的對(duì)象時(shí)。
在 Java
中耕餐,萬(wàn)物皆對(duì)象凡傅,這些對(duì)象都需要?jiǎng)?chuàng)建,如果創(chuàng)建的時(shí)候直接 new
該對(duì)象肠缔,就會(huì)對(duì)該對(duì)象耦合嚴(yán)重夏跷,假如我們要更換對(duì)象,所有 new
對(duì)象的地方都需要修改一遍明未,這顯然違背了軟件設(shè)計(jì)的開(kāi)閉原則槽华。如果我們使用工廠來(lái)生產(chǎn)對(duì)象,我們就只和工廠打交道就可以了趟妥,徹底和對(duì)象解耦猫态,如果要更換對(duì)象,直接在工廠里更換該對(duì)象即可,達(dá)到了與對(duì)象解耦的目的亲雪。所以說(shuō)勇凭,工廠模式最大的優(yōu)點(diǎn)就是:解耦。
工廠模式主要分為以下幾種類(lèi)型:
- 簡(jiǎn)單工廠模式(Simple Factory)
- 工廠方法模式(Factory Method)
- 抽象工廠模式(Abstract Factory)
1.2 場(chǎng)景:操作不同類(lèi)型的動(dòng)物
我們假設(shè)有一個(gè)場(chǎng)景义辕,程序需要對(duì)不同種類(lèi)的動(dòng)物進(jìn)行操作套像,動(dòng)物可以發(fā)出不同的聲音。
1.2.1 不用工廠模式
1.2.1.1 分析
在這個(gè)例子中终息,客戶(hù)端代碼直接依賴(lài)于具體的動(dòng)物類(lèi) ( Dog
, Cat
, Bird
)夺巩,這意味著如果我們添加新的動(dòng)物類(lèi)型或者更改現(xiàn)有的創(chuàng)建邏輯,必須修改客戶(hù)端代碼周崭。這種實(shí)現(xiàn)方式耦合度較高柳譬,不符合開(kāi)閉原則。
類(lèi)圖:
// 動(dòng)物接口
interface Animal {
void makeSound();
}
// 具體動(dòng)物類(lèi):狗
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Woof");
}
}
// 具體動(dòng)物類(lèi):貓
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("Meow");
}
}
// 具體動(dòng)物類(lèi):鳥(niǎo)
class Bird implements Animal {
@Override
public void makeSound() {
System.out.println("Tweet");
}
}
// 客戶(hù)端代碼
public class Client {
public static void main(String[] args) {
// 客戶(hù)端直接實(shí)例化
Animal animal1 = new Dog();
// 輸出:Woof
animal1.makeSound();
Animal animal2 = new Cat();
// 輸出:Meow
animal2.makeSound();
Animal animal3 = new Bird();
// 輸出:Tweet
animal3.makeSound();
}
}
1.2.1.1 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
- 簡(jiǎn)單直接:客戶(hù)端直接實(shí)例化對(duì)象续镇,代碼較為簡(jiǎn)單美澳,適用于對(duì)象數(shù)量少、變動(dòng)少的情況摸航。
- 缺點(diǎn):
- 高耦合性:客戶(hù)端依賴(lài)具體類(lèi)制跟,任何對(duì)象的變化(如新增類(lèi)、修改類(lèi))都需要修改客戶(hù)端代碼酱虎,違反開(kāi)閉原則雨膨。
- 擴(kuò)展性差:當(dāng)新增或修改對(duì)象時(shí),需要改動(dòng)已有代碼读串,且對(duì)不同條件的判斷邏輯可能會(huì)擴(kuò)散到多個(gè)地方聊记。
1.2.2 簡(jiǎn)單工廠模式
簡(jiǎn)單工廠模式使用一個(gè)單獨(dú)的類(lèi)根據(jù)參數(shù)創(chuàng)建不同類(lèi)型的對(duì)象。它是一種具體的工廠恢暖,不屬于設(shè)計(jì)模式中的 23
種經(jīng)典設(shè)計(jì)模式排监,但經(jīng)常被用作學(xué)習(xí)的起點(diǎn)。
1.2.2.1 結(jié)構(gòu)
簡(jiǎn)單工廠包含如下角色:
- 抽象產(chǎn)品 :定義了產(chǎn)品的規(guī)范杰捂,描述了產(chǎn)品的主要特性和功能舆床。
- 具體產(chǎn)品 :實(shí)現(xiàn)或者繼承抽象產(chǎn)品的子類(lèi)
- 具體工廠 :提供了創(chuàng)建產(chǎn)品的方法,調(diào)用者通過(guò)該方法來(lái)獲取產(chǎn)品嫁佳。
1.2.2.2 分析
- 在簡(jiǎn)單工廠模式中挨队,
AnimalFactory
類(lèi)封裝了對(duì)象的創(chuàng)建邏輯,客戶(hù)端只需要傳遞參數(shù)來(lái)指定創(chuàng)建的動(dòng)物類(lèi)型脱拼,而無(wú)需知道具體的類(lèi)瞒瘸。 - 雖然解決了直接依賴(lài)具體類(lèi)的問(wèn)題,但如果我們想添加新的動(dòng)物類(lèi)型熄浓,仍需要修改
AnimalFactory
類(lèi)的邏輯情臭,這違反了開(kāi)閉原則省撑。
類(lèi)圖:
// 簡(jiǎn)單工廠類(lèi)
class AnimalFactory {
public Animal createAnimal(String type) {
if ("Dog".equalsIgnoreCase(type)) {
return new Dog();
} else if ("Cat".equalsIgnoreCase(type)) {
return new Cat();
} else if ("Bird".equalsIgnoreCase(type)) {
return new Bird();
} else {
throw new IllegalArgumentException("Unknown animal type");
}
}
}
// 客戶(hù)端代碼
public class Client {
public static void main(String[] args) {
AnimalFactory factory = new AnimalFactory();
Animal animal1 = factory.createAnimal("Dog");
// 輸出:Woof
animal1.makeSound();
Animal animal2 = factory.createAnimal("Cat");
// 輸出:Meow
animal2.makeSound();
Animal animal3 = factory.createAnimal("Bird");
// 輸出:Tweet
animal3.makeSound();
}
}
1.2.1.3 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
- 創(chuàng)建邏輯集中:將對(duì)象的創(chuàng)建集中在一個(gè)工廠類(lèi)中,客戶(hù)端只需知道要?jiǎng)?chuàng)建的對(duì)象類(lèi)型(傳遞字符串或參數(shù))俯在,降低了對(duì)具體類(lèi)的依賴(lài)竟秫。
- 簡(jiǎn)化客戶(hù)端代碼:客戶(hù)端不再負(fù)責(zé)具體對(duì)象的創(chuàng)建,只需調(diào)用工廠方法跷乐。
- 缺點(diǎn):
-
違反開(kāi)閉原則:如果需要添加新的類(lèi)型肥败,需要修改工廠類(lèi)的創(chuàng)建邏輯(
if-else
或switch-case
語(yǔ)句)。 - 復(fù)雜性增加:隨著對(duì)象類(lèi)型增多愕提,工廠類(lèi)的創(chuàng)建邏輯可能變得復(fù)雜馒稍,不利于維護(hù)。
1.2.1.4 擴(kuò)展:靜態(tài)工廠
在開(kāi)發(fā)中也有一部分人將工廠類(lèi)中的創(chuàng)建對(duì)象的功能定義為靜態(tài)的浅侨,這個(gè)就是靜態(tài)工廠模式纽谒,它也不是 23
種設(shè)計(jì)模式中的。
類(lèi)圖:
// 靜態(tài)工廠類(lèi)
class AnimalFactory {
public static Animal createAnimal(String type) {
if ("Dog".equalsIgnoreCase(type)) {
return new Dog();
} else if ("Cat".equalsIgnoreCase(type)) {
return new Cat();
} else if ("Bird".equalsIgnoreCase(type)) {
return new Bird();
} else {
throw new IllegalArgumentException("Unknown animal type");
}
}
}
// 客戶(hù)端代碼
public class Client {
public static void main(String[] args) {
Animal animal1 = AnimalFactory.createAnimal("Dog");
// 輸出:Woof
animal1.makeSound();
Animal animal2 = AnimalFactory.createAnimal("Cat");
// 輸出:Meow
animal2.makeSound();
Animal animal3 = AnimalFactory.createAnimal("Bird");
// 輸出:Tweet
animal3.makeSound();
}
}
1.2.3 工廠方法模式
工廠方法模式定義了一個(gè)創(chuàng)建對(duì)象的接口如输,但讓子類(lèi)決定實(shí)例化哪個(gè)類(lèi)鼓黔。工廠方法模式將對(duì)象的創(chuàng)建推遲到子類(lèi)。
1.2.3.1 結(jié)構(gòu)
工廠方法模式的主要角色:
- 抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口不见,調(diào)用者通過(guò)它訪問(wèn)具體工廠的工廠方法來(lái)創(chuàng)建產(chǎn)品澳化。抽象工廠既可以是接口也可以是抽象類(lèi),具體使用哪種形式取決于具體的設(shè)計(jì)需求和場(chǎng)景稳吮。
- 具體工廠(ConcreteFactory):主要是實(shí)現(xiàn)抽象工廠中的抽象方法缎谷,完成具體產(chǎn)品的創(chuàng)建。
- 抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范盖高,描述了產(chǎn)品的主要特性和功能慎陵。
- 具體產(chǎn)品(ConcreteProduct):實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口眼虱,由具體工廠來(lái)創(chuàng)建喻奥,它同具體工廠之間一一對(duì)應(yīng)。
1.2.3.2 分析
- 在工廠方法模式中捏悬,每個(gè)具體的動(dòng)物都有一個(gè)對(duì)應(yīng)的工廠類(lèi)撞蚕,工廠類(lèi)負(fù)責(zé)創(chuàng)建對(duì)應(yīng)的動(dòng)物實(shí)例。
- 這種模式遵循了開(kāi)閉原則过牙,添加新的動(dòng)物類(lèi)型只需新建一個(gè)工廠類(lèi)和對(duì)應(yīng)的動(dòng)物類(lèi)甥厦,而無(wú)需修改現(xiàn)有代碼。
類(lèi)圖:
// 抽象工廠類(lèi)
abstract class AnimalFactory {
public abstract Animal createAnimal();
}
// 具體工廠類(lèi):狗工廠類(lèi)
class DogFactory extends AnimalFactory{
@Override
public Animal createAnimal() {
return new Dog();
}
}
// 具體工廠類(lèi):貓工廠類(lèi)
class CatFactory extends AnimalFactory{
@Override
public Animal createAnimal() {
return new Cat();
}
}
// 具體工廠類(lèi):鳥(niǎo)工廠類(lèi)
class BirdFactory extends AnimalFactory{
@Override
public Animal createAnimal() {
return new Bird();
}
}
// 客戶(hù)端代碼
public class Client {
public static void main(String[] args) {
AnimalFactory factory1 = new DogFactory();
Animal animal1 = factory1.createAnimal();
// 輸出:Woof
animal1.makeSound();
AnimalFactory factory2 = new CatFactory();
Animal animal2 = factory2.createAnimal();
// 輸出:Meow
animal2.makeSound();
AnimalFactory factory3 = new BirdFactory();
Animal animal3 = factory3.createAnimal();
// 輸出:Tweet
animal3.makeSound();
}
}
1.2.3.3 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
- 符合開(kāi)閉原則:工廠方法模式通過(guò)新增具體工廠類(lèi)來(lái)擴(kuò)展產(chǎn)品類(lèi)型寇钉,而不修改已有代碼刀疙,符合開(kāi)閉原則。
- 解耦合:客戶(hù)端不再依賴(lài)于具體類(lèi)扫倡,而是依賴(lài)于抽象工廠接口谦秧,提升了代碼的可擴(kuò)展性和靈活性。
- 職責(zé)分離:每個(gè)工廠負(fù)責(zé)創(chuàng)建一種產(chǎn)品,工廠類(lèi)和產(chǎn)品類(lèi)的職責(zé)更加明確疚鲤,便于維護(hù)锥累。
- 缺點(diǎn):
- 增加類(lèi)的數(shù)量:每增加一種產(chǎn)品類(lèi)型,都需要新建對(duì)應(yīng)的工廠類(lèi)集歇,這會(huì)使類(lèi)的數(shù)量增多桶略,增加代碼的復(fù)雜性。
- 適用場(chǎng)景有限:適合有多個(gè)類(lèi)型的產(chǎn)品且產(chǎn)品類(lèi)型較穩(wěn)定的場(chǎng)景诲宇。如果產(chǎn)品類(lèi)型非常多际歼,工廠方法模式可能顯得冗余。
1.2.4 抽象工廠模式
抽象工廠模式提供了一個(gè)接口姑蓝,用于創(chuàng)建一系列相關(guān)或相互依賴(lài)的對(duì)象蹬挺,而無(wú)需指定它們的具體類(lèi)。它通常用于需要?jiǎng)?chuàng)建多個(gè)相關(guān)產(chǎn)品的場(chǎng)景它掂。
1.2.4.1 結(jié)構(gòu)
抽象工廠模式的主要角色如下:
- 抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口巴帮,它包含多個(gè)創(chuàng)建產(chǎn)品的方法餐济,可以創(chuàng)建多個(gè)不同等級(jí)的產(chǎn)品剂陡。抽象工廠既可以是接口也可以是抽象類(lèi),具體使用哪種形式取決于具體的設(shè)計(jì)需求和場(chǎng)景诽偷。
- 具體工廠(Concrete Factory):主要是實(shí)現(xiàn)抽象工廠中的多個(gè)抽象方法客给,完成具體產(chǎn)品的創(chuàng)建用押。
- 抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能靶剑,抽象工廠模式有多個(gè)抽象產(chǎn)品蜻拨。
- 具體產(chǎn)品(ConcreteProduct):實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來(lái)創(chuàng)建桩引,它 同具體工廠之間是多對(duì)一的關(guān)系缎讼。
1.2.4.2 分析
- 在抽象工廠模式中,
AnimalFactory
提供了創(chuàng)建動(dòng)物和食物的接口坑匠。不同的具體工廠(DogFactory
血崭、CatFactory
、BirdFactory
)負(fù)責(zé)創(chuàng)建不同的動(dòng)物及其食物厘灼。 - 這種模式適合在需要?jiǎng)?chuàng)建相關(guān)產(chǎn)品族時(shí)使用夹纫,比如同一類(lèi)的動(dòng)物和它們的食物。在不修改已有工廠的情況下设凹,可以擴(kuò)展新的動(dòng)物和食物種類(lèi)舰讹。
類(lèi)圖:
// 食物接口
interface Food {
void eat();
}
// 具體食物類(lèi):狗糧
class DogFood implements Food {
@Override
public void eat() {
System.out.println("Dog is eating dog food.");
}
}
// 具體食物類(lèi):貓糧
class CatFood implements Food {
@Override
public void eat() {
System.out.println("Cat is eating cat food.");
}
}
// 具體食物類(lèi):鳥(niǎo)糧
class BirdFood implements Food {
@Override
public void eat() {
System.out.println("Bird is eating bird seeds.");
}
}
// 抽象工廠類(lèi)
interface AnimalFactory {
Animal createAnimal();
Food createFood();
}
// 具體工廠類(lèi):狗工廠類(lèi)
class DogFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
@Override
public Food createFood() {
return new DogFood();
}
}
// 具體工廠類(lèi):貓工廠類(lèi)
class CatFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
@Override
public Food createFood() {
return new CatFood();
}
}
// 具體工廠類(lèi):鳥(niǎo)工廠類(lèi)
class BirdFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Bird();
}
@Override
public Food createFood() {
return new BirdFood();
}
}
// 客戶(hù)端代碼
public class Client {
public static void main(String[] args) {
AnimalFactory factory1 = new DogFactory();
Animal animal1 = factory1.createAnimal();
Food food1 = factory1.createFood();
// 輸出:Woof
animal1.makeSound();
// 輸出:Dog is eating dog food.
food1.eat();
AnimalFactory factory2 = new CatFactory();
Animal animal2 = factory2.createAnimal();
Food food2 = factory2.createFood();
// 輸出:Meow
animal2.makeSound();
// 輸出:Cat is eating cat food.
food2.eat();
AnimalFactory factory3 = new BirdFactory();
Animal animal3 = factory3.createAnimal();
Food food3 = factory3.createFood();
// 輸出:Tweet
animal3.makeSound();
// 輸出:Bird is eating bird seeds.
food3.eat();
}
}
1.2.4.3 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
- 產(chǎn)品族管理:能夠創(chuàng)建相關(guān)聯(lián)的一系列產(chǎn)品(即產(chǎn)品族),適合創(chuàng)建一組相互依賴(lài)的對(duì)象闪朱,如某一類(lèi)產(chǎn)品和它的配件月匣。
- 解耦產(chǎn)品族與客戶(hù)端:客戶(hù)端不關(guān)心產(chǎn)品的具體實(shí)現(xiàn)匈睁,而是通過(guò)抽象工廠統(tǒng)一獲取產(chǎn)品,降低了代碼的耦合度桶错。
- 符合開(kāi)閉原則:可以通過(guò)擴(kuò)展工廠來(lái)增加新的產(chǎn)品族航唆,而不修改已有代碼,符合開(kāi)閉原則院刁。
- 缺點(diǎn):
- 復(fù)雜度高:抽象工廠模式的結(jié)構(gòu)復(fù)雜糯钙,增加了類(lèi)和接口的數(shù)量,導(dǎo)致系統(tǒng)變得臃腫退腥,尤其是在不需要?jiǎng)?chuàng)建產(chǎn)品族的情況下任岸。
- 擴(kuò)展產(chǎn)品等級(jí)結(jié)構(gòu)困難:雖然易于擴(kuò)展產(chǎn)品族(增加一組新產(chǎn)品),但如果需要為已有的產(chǎn)品族增加新的產(chǎn)品等級(jí)結(jié)構(gòu)(如在已有的產(chǎn)品類(lèi)中再增加一個(gè)功能)狡刘,需要修改所有的工廠接口和具體工廠類(lèi)享潜。
1.2.5 抽象工廠模式和工廠方法模式的區(qū)別與聯(lián)系
抽象工廠模式 是 工廠方法模式 的擴(kuò)展。抽象工廠模式解決了 多個(gè)相關(guān)產(chǎn)品 一起創(chuàng)建的需求嗅蔬,而工廠方法模式只處理單一產(chǎn)品的創(chuàng)建
1.2.5.1 聯(lián)系
工廠方法模式:主要用于創(chuàng)建 單個(gè)產(chǎn)品剑按。每個(gè)具體的工廠類(lèi)負(fù)責(zé)創(chuàng)建一種具體的產(chǎn)品,工廠方法模式的重點(diǎn)是為某個(gè)類(lèi)型的產(chǎn)品提供創(chuàng)建方法澜术,客戶(hù)端通過(guò)調(diào)用工廠接口來(lái)創(chuàng)建產(chǎn)品對(duì)象艺蝴。
抽象工廠模式:不僅僅創(chuàng)建單個(gè)產(chǎn)品,而是用于創(chuàng)建一系列相關(guān)的產(chǎn)品族鸟废。抽象工廠為不同的產(chǎn)品族提供接口猜敢,允許客戶(hù)端使用不同的具體工廠來(lái)創(chuàng)建整個(gè)產(chǎn)品族中的所有產(chǎn)品,而不需要修改客戶(hù)端代碼盒延。
1.2.5.2 不同點(diǎn)
-
產(chǎn)品的數(shù)量:
- 工廠方法模式:一個(gè)工廠類(lèi)只創(chuàng)建一個(gè)產(chǎn)品缩擂。
- 抽象工廠模式:一個(gè)工廠類(lèi)可以創(chuàng)建多個(gè)相關(guān)的產(chǎn)品(即產(chǎn)品族)。
-
復(fù)雜度:
- 工廠方法模式相對(duì)較簡(jiǎn)單添寺,關(guān)注于單一產(chǎn)品的創(chuàng)建胯盯。
- 抽象工廠模式更加復(fù)雜,適用于有多個(gè)產(chǎn)品需要同時(shí)創(chuàng)建畦贸,且這些產(chǎn)品通常是有內(nèi)在關(guān)聯(lián)的情況陨闹。
1.3 總結(jié)
- 不用工廠模式:簡(jiǎn)單但耦合度高,擴(kuò)展性差薄坏。
- 簡(jiǎn)單工廠模式:將對(duì)象的創(chuàng)建邏輯集中管理,但擴(kuò)展性差寨闹,違反開(kāi)閉原則胶坠。
- 工廠方法模式:符合開(kāi)閉原則,增加擴(kuò)展性繁堡,適合單個(gè)產(chǎn)品的創(chuàng)建沈善,但類(lèi)數(shù)量增多乡数。
- 抽象工廠模式:適合創(chuàng)建一組相關(guān)產(chǎn)品,能管理產(chǎn)品族闻牡,擴(kuò)展性強(qiáng)净赴,但實(shí)現(xiàn)復(fù)雜,增加了系統(tǒng)的難度罩润。
1.4 通過(guò) 簡(jiǎn)單工廠模式+配置文件 解除耦合
通過(guò)簡(jiǎn)單工廠模式和配置文件的結(jié)合玖翅,可以有效解除客戶(hù)端和具體產(chǎn)品類(lèi)之間的耦合。這種方式通過(guò)在配置文件中配置具體產(chǎn)品類(lèi)的名稱(chēng)或類(lèi)型割以,簡(jiǎn)單工廠讀取配置文件動(dòng)態(tài)創(chuàng)建對(duì)象金度,從而讓客戶(hù)端不需要直接依賴(lài)具體類(lèi)。這樣如果以后要替換或新增產(chǎn)品严沥,客戶(hù)端代碼無(wú)需修改猜极,只需要更新配置文件和相應(yīng)的工廠邏輯。
1.4.1 步驟分析
- 配置文件:將需要?jiǎng)?chuàng)建的類(lèi)(具體產(chǎn)品)的信息存儲(chǔ)在配置文件中消玄,工廠可以根據(jù)該配置文件動(dòng)態(tài)加載類(lèi)跟伏。
- 簡(jiǎn)單工廠模式:根據(jù)讀取到的配置文件的內(nèi)容,工廠通過(guò)反射等機(jī)制動(dòng)態(tài)創(chuàng)建具體的產(chǎn)品對(duì)象翩瓜。
- 解除耦合:客戶(hù)端不再直接依賴(lài)具體的產(chǎn)品類(lèi)酬姆,而是依賴(lài)工廠類(lèi)。通過(guò)工廠類(lèi)讀取配置文件奥溺,靈活地創(chuàng)建不同的產(chǎn)品辞色。
1.4.2 例子
類(lèi)圖:
配置文件 (config.properties
):配置文件中指定了產(chǎn)品類(lèi)的全限定類(lèi)名,便于工廠動(dòng)態(tài)讀取和創(chuàng)建實(shí)例浮定。
Dog=patterns.factory.Implementation.after.configfactory.Dog
Cat=patterns.factory.Implementation.after.configfactory.Cat
Bird=patterns.factory.Implementation.after.configfactory.Bird
// 簡(jiǎn)單工廠類(lèi)+配置文件
class AnimalFactory {
// 加載配置文件相满,獲取配置文件中配置的全類(lèi)名,并創(chuàng)建該類(lèi)的對(duì)象進(jìn)行存儲(chǔ)
private static HashMap<String, Animal> map = new HashMap<>();
// 加載配置文件桦卒, 只需要加載一次
static {
// 根據(jù)配置文件創(chuàng)建產(chǎn)品對(duì)象
Properties properties = new Properties();
InputStream in = AnimalFactory.class.getClassLoader().getResourceAsStream("config.properties");
try {
properties.load(in);
// 從配置文件對(duì)象中獲取全類(lèi)名并創(chuàng)建對(duì)象
Set<Object> keys = properties.keySet();
for (Object key : keys) {
String className = properties.getProperty((String) key);
// 通過(guò)反射技術(shù)創(chuàng)建對(duì)象
Class<?> clazz = Class.forName(className);
Animal animal = (Animal) clazz.getDeclaredConstructor().newInstance();
// 將名稱(chēng)和對(duì)象存儲(chǔ)到容器中
map.put(((String) key).toLowerCase(), animal);
}
if (in != null) {
in.close();
}
} catch (IOException | ReflectiveOperationException e) {
e.printStackTrace();
}
}
public static Animal createAnimal(String type) {
return map.get(type.toLowerCase());
}
}
// 客戶(hù)端代碼
public class Client {
public static void main(String[] args) {
// 客戶(hù)端通過(guò)工廠獲取具體產(chǎn)品立美,而不關(guān)心具體產(chǎn)品的實(shí)現(xiàn)
Animal animal1 = AnimalFactory.createAnimal("Dog");
// 輸出:Woof
animal1.makeSound();
Animal animal2 = AnimalFactory.createAnimal("Cat");
// 輸出:Meow
animal2.makeSound();
Animal animal3 = AnimalFactory.createAnimal("Bird");
// 輸出:Tweet
animal3.makeSound();
}
}
1.4.3 關(guān)鍵點(diǎn)
配置文件:配置文件
config.properties
存儲(chǔ)了具體類(lèi)的類(lèi)名信息,這樣可以方便更改具體的實(shí)現(xiàn)方灾。比如建蹄,修改配置文件中的Dog
為Cat
,就會(huì)創(chuàng)建Cat
類(lèi)的對(duì)象裕偿,而不需要修改客戶(hù)端代碼洞慎。反射機(jī)制:工廠通過(guò)反射動(dòng)態(tài)加載配置文件中的類(lèi)名,并創(chuàng)建對(duì)應(yīng)的實(shí)例嘿棘。
解耦合:客戶(hù)端不再依賴(lài)于具體的
Dog
或Cat
類(lèi)劲腿,而是依賴(lài)于工廠,工廠通過(guò)配置文件靈活創(chuàng)建實(shí)例鸟妙。即便以后新增其他Animal
實(shí)現(xiàn)類(lèi)焦人,客戶(hù)端也無(wú)需修改挥吵,只需調(diào)整配置文件。
1.4.4 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
- 低耦合:客戶(hù)端不直接依賴(lài)具體產(chǎn)品花椭,具體產(chǎn)品類(lèi)可以靈活替換忽匈。
- 擴(kuò)展性強(qiáng):通過(guò)修改配置文件即可動(dòng)態(tài)替換不同的產(chǎn)品類(lèi),而不影響代碼矿辽。
- 維護(hù)性好:新增產(chǎn)品時(shí)丹允,只需新增實(shí)現(xiàn)類(lèi)和配置,而不需要修改客戶(hù)端代碼嗦锐。
- 缺點(diǎn):
- 反射開(kāi)銷(xiāo):使用反射機(jī)制會(huì)帶來(lái)一定的性能開(kāi)銷(xiāo)嫌松,且在編譯期無(wú)法檢測(cè)類(lèi)的有效性,容易在運(yùn)行時(shí)出現(xiàn)錯(cuò)誤奕污。
- 配置管理:需要額外的配置文件管理萎羔。
1.5 JDK源碼解析-Collection.iterator方法
Collection.iterator()
方法的設(shè)計(jì)實(shí)際上可以看作是工廠模式的一個(gè)應(yīng)用。雖然工廠模式在經(jīng)典的形式中通常用于創(chuàng)建獨(dú)立的對(duì)象碳默,但在 Java 的集合框架中贾陷,iterator()
方法提供了類(lèi)似工廠模式的功能:它通過(guò)接口返回一個(gè) Iterator
對(duì)象,而不用暴露 Iterator
的具體實(shí)現(xiàn)嘱根,符合工廠模式的核心思想髓废,即將對(duì)象的創(chuàng)建和使用分離。
類(lèi)圖:
1.5.1 Iterator 和 Collection
Iterator
是 Java 集合框架中的一個(gè)接口该抒,允許客戶(hù)端在不知道集合內(nèi)部實(shí)現(xiàn)的情況下進(jìn)行遍歷慌洪。Collection
是所有集合類(lèi)的頂層接口,如 List
凑保、Set
冈爹、Queue
等都實(shí)現(xiàn)了這個(gè)接口。而 iterator()
方法則是 Collection
接口中的一個(gè)方法欧引,它返回該集合元素的迭代器(Iterator
)频伤,用于遍歷集合。
1.5.2 如何體現(xiàn)工廠模式
工廠模式的核心思想是:
- 提供一個(gè)接口芝此,用于創(chuàng)建對(duì)象憋肖。
- 隱藏具體實(shí)現(xiàn),讓客戶(hù)端只關(guān)心接口婚苹,不關(guān)心具體實(shí)現(xiàn)岸更。
iterator()
方法符合這種思路,它提供一個(gè)接口 Iterator
來(lái)遍歷集合租副,而客戶(hù)端并不需要關(guān)心具體集合類(lèi)是如何實(shí)現(xiàn) Iterator
的坐慰。
-
Collection 是集合的頂層接口,定義了
iterator()
方法用僧。 -
Iterator 是迭代器的接口结胀,定義了迭代器需要的方法,如
hasNext()
责循、next()
糟港、remove()
。 -
List 和 Set 分別實(shí)現(xiàn)了
Collection
接口院仿,提供了具體的iterator()
實(shí)現(xiàn)秸抚。它們返回的是各自特定的迭代器。
1.5.4 工廠模式的體現(xiàn)
-
Collection
接口中的iterator()
方法就像是一個(gè)工廠方法歹垫,返回Iterator
對(duì)象剥汤。 - 每個(gè)具體的集合類(lèi)(如
List
和Set
)都提供了自己的iterator()
實(shí)現(xiàn)。這相當(dāng)于工廠方法中的不同工廠類(lèi)排惨,返回不同的產(chǎn)品對(duì)象(不同的Iterator
實(shí)現(xiàn))吭敢。 - 客戶(hù)端調(diào)用
iterator()
后,得到的是Iterator
接口暮芭,而不是具體的Iterator
實(shí)現(xiàn)類(lèi)鹿驼。這種方式屏蔽了集合內(nèi)部的實(shí)現(xiàn)細(xì)節(jié),客戶(hù)端不需要關(guān)心集合的具體類(lèi)型辕宏,只需要按照Iterator
接口的規(guī)范來(lái)操作集合畜晰。
1.5.4.1 Collection 接口(簡(jiǎn)化版)
public interface Collection<E> {
Iterator<E> iterator();
}
1.5.4.2 List 和 Set 類(lèi)
public class Client {
public static void main(String[] args) {
// 使用ArrayList的迭代器
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Iterator<String> listIterator = list.iterator();
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
// 使用HashSet的迭代器
HashSet<String> set = new HashSet<>();
set.add("X");
set.add("Y");
set.add("Z");
Iterator<String> setIterator = set.iterator();
while (setIterator.hasNext()) {
System.out.println(setIterator.next());
}
}
}
1.5.5 工廠模式的優(yōu)缺點(diǎn)在 Collection.iterator()
中的體現(xiàn)
- 優(yōu)點(diǎn):
-
解耦:客戶(hù)端無(wú)需知道集合的具體實(shí)現(xiàn),只需要通過(guò)
Iterator
接口來(lái)進(jìn)行遍歷瑞筐。無(wú)論是List
凄鼻、Set
還是其他集合類(lèi)型,都提供統(tǒng)一的遍歷方式聚假。 -
擴(kuò)展性強(qiáng):如果添加新的集合類(lèi)型块蚌,只需要提供自己的
iterator()
實(shí)現(xiàn)即可,客戶(hù)端不需要做任何修改魔策。
- 缺點(diǎn):
- 工廠模式可能會(huì)導(dǎo)致類(lèi)的數(shù)量增加匈子,因?yàn)槊糠N具體集合類(lèi)型都需要提供自己的迭代器實(shí)現(xiàn)。