第四天:工廠方法模式、抽象工廠模式

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)型:

  1. 簡(jiǎn)單工廠模式(Simple Factory)
  2. 工廠方法模式(Factory Method)
  3. 抽象工廠模式(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)圖:

image.png
// 動(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)

  1. 優(yōu)點(diǎn):
  • 簡(jiǎn)單直接:客戶(hù)端直接實(shí)例化對(duì)象续镇,代碼較為簡(jiǎn)單美澳,適用于對(duì)象數(shù)量少、變動(dòng)少的情況摸航。
  1. 缺點(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)圖:

image.png
// 簡(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)

  1. 優(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)用工廠方法跷乐。
  1. 缺點(diǎn):
  • 違反開(kāi)閉原則:如果需要添加新的類(lèi)型肥败,需要修改工廠類(lèi)的創(chuàng)建邏輯(if-elseswitch-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)圖:

image.png
// 靜態(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)圖:

image.png
// 抽象工廠類(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)

  1. 優(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ù)锥累。
  1. 缺點(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血崭、CatFactoryBirdFactory)負(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)圖:

image.png
// 食物接口
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)

  1. 優(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)閉原則院刁。
  1. 缺點(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)

  1. 產(chǎn)品的數(shù)量

    • 工廠方法模式:一個(gè)工廠類(lèi)只創(chuàng)建一個(gè)產(chǎn)品缩擂。
    • 抽象工廠模式:一個(gè)工廠類(lèi)可以創(chuàng)建多個(gè)相關(guān)的產(chǎn)品(即產(chǎn)品族)。
  2. 復(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 步驟分析

  1. 配置文件:將需要?jiǎng)?chuàng)建的類(lèi)(具體產(chǎn)品)的信息存儲(chǔ)在配置文件中消玄,工廠可以根據(jù)該配置文件動(dòng)態(tài)加載類(lèi)跟伏。
  2. 簡(jiǎn)單工廠模式:根據(jù)讀取到的配置文件的內(nèi)容,工廠通過(guò)反射等機(jī)制動(dòng)態(tài)創(chuàng)建具體的產(chǎn)品對(duì)象翩瓜。
  3. 解除耦合:客戶(hù)端不再直接依賴(lài)具體的產(chǎn)品類(lèi)酬姆,而是依賴(lài)工廠類(lèi)。通過(guò)工廠類(lèi)讀取配置文件奥溺,靈活地創(chuàng)建不同的產(chǎn)品辞色。

1.4.2 例子

類(lèi)圖:

image.png

配置文件 (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)

  1. 配置文件:配置文件 config.properties 存儲(chǔ)了具體類(lèi)的類(lèi)名信息,這樣可以方便更改具體的實(shí)現(xiàn)方灾。比如建蹄,修改配置文件中的 DogCat,就會(huì)創(chuàng)建 Cat 類(lèi)的對(duì)象裕偿,而不需要修改客戶(hù)端代碼洞慎。

  2. 反射機(jī)制:工廠通過(guò)反射動(dòng)態(tài)加載配置文件中的類(lèi)名,并創(chuàng)建對(duì)應(yīng)的實(shí)例嘿棘。

  3. 解耦合:客戶(hù)端不再依賴(lài)于具體的 DogCat 類(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)

  1. 優(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ù)端代碼嗦锐。
  1. 缺點(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)圖:

image.png

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()
  • ListSet 分別實(shí)現(xiàn)了 Collection 接口院仿,提供了具體的 iterator() 實(shí)現(xiàn)秸抚。它們返回的是各自特定的迭代器。

1.5.4 工廠模式的體現(xiàn)

  • Collection 接口中的 iterator() 方法就像是一個(gè)工廠方法歹垫,返回 Iterator 對(duì)象剥汤。
  • 每個(gè)具體的集合類(lèi)(如 ListSet)都提供了自己的 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)

  1. 優(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ù)端不需要做任何修改魔策。
  1. 缺點(diǎn):
  • 工廠模式可能會(huì)導(dǎo)致類(lèi)的數(shù)量增加匈子,因?yàn)槊糠N具體集合類(lèi)型都需要提供自己的迭代器實(shí)現(xiàn)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末闯袒,一起剝皮案震驚了整個(gè)濱河市虎敦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌政敢,老刑警劉巖其徙,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異喷户,居然都是意外死亡唾那,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)褪尝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)闹获,“玉大人期犬,你說(shuō)我怎么就攤上這事”芊蹋” “怎么了龟虎?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)沙庐。 經(jīng)常有香客問(wèn)我鲤妥,道長(zhǎng),這世上最難降的妖魔是什么拱雏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任棉安,我火速辦了婚禮,結(jié)果婚禮上铸抑,老公的妹妹穿的比我還像新娘贡耽。我一直安慰自己,他們只是感情好羡滑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布菇爪。 她就那樣靜靜地躺著,像睡著了一般柒昏。 火紅的嫁衣襯著肌膚如雪凳宙。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天职祷,我揣著相機(jī)與錄音氏涩,去河邊找鬼。 笑死有梆,一個(gè)胖子當(dāng)著我的面吹牛是尖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播泥耀,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼饺汹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了痰催?” 一聲冷哼從身側(cè)響起兜辞,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎夸溶,沒(méi)想到半個(gè)月后逸吵,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缝裁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年扫皱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡韩脑,死狀恐怖氢妈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扰才,我是刑警寧澤允懂,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布厕怜,位于F島的核電站衩匣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏粥航。R本人自食惡果不足惜琅捏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望递雀。 院中可真熱鬧柄延,春花似錦、人聲如沸缀程。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)杨凑。三九已至滤奈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撩满,已是汗流浹背蜒程。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伺帘,地道東北人昭躺。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像伪嫁,于是被迫代替她去往敵國(guó)和親领炫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容