AI Chat 设计模式:2. 工厂设计模式

news2024/11/17 10:51:57

本文是该系列的第二篇,采用问答式的方式展开,问题由我提出,答案由 Chat AI 作出,灰色背景的文字则主要是我的旁白。

问题列表

  • Q.1 介绍下工厂设计模式
  • A.1
  • Q.2 这种设计模式有哪几种形式
  • A.2
  • Q.3 使用c++写一个简单工厂的例子
  • A.3
  • Q.4 我希望例子更贴近生活一些,你这个有点抽象
  • A.4
  • Q.5 这个例子很好,继续使用这个例子,写一下工厂方法模式的代码
  • A.5
  • Q.6 好,继续使用这个例子,实现一下抽象工厂模式
  • A.6
  • Q.7 有个疑问,CreateCatFood 和 CreateDogFood 这两个方法是不是统一为 CreateFood 更好
  • A.7
  • Q.8 我理解的,狗工厂和猫工厂是两个工厂,狗、狗粮是一个产品族,狗粮和猫粮并不是一个产品族
  • A.8
  • Q.9 那既然如此,CreateCatFood 和 CreateDogFood 就应该统一为一个方法 CreateFood ,就像狗和猫的生产那样
  • A.9
  • Q.10 我还是不太理解你开始为什么要写 CreateCatFood 和CreateDogFood 这两个方法,能换个例子给我讲清楚吗
  • A.10
  • Q.11 那我认为你在宠物的例子中犯了错,就像苹果工厂不能生产小米配件一样,狗工厂也不应该能生产猫粮。
  • A.11
  • Q.12 最后总结下三种工厂模式的优缺点吧
  • A.12
  • Q.13 画一下它们的类图吧
  • A.13
    • 11.1 简单工厂模式类图
    • 11.2 工厂方法模式类图
    • 11.3 抽象工厂模式类图
    • 11.4 再画一下抽象工厂模式的产品族示意图

Q.1 介绍下工厂设计模式

A.1

工厂设计模式是一种创建型设计模式,旨在解决对象的创建和实例化过程中的一些问题。通常情况下,我们可以通过直接在代码中使用 new 关键字创建对象实例,但是在某些场景下,我们可能需要更加灵活、可扩展的创建方式,以简化代码并提高可维护性。

工厂模式通过引入一个专门的“工厂”对象来创建和生成对象实例,从而将对象的创建和实例化过程完全隔离开来。这个“工厂”对象承担了所有的创建和实例化逻辑,客户端代码只需要向它提供所需的参数以及需要的对象类型,就能够得到一个完整的可用对象实例。

工厂模式通常会包括一个工厂接口多个具体的工厂实现每个工厂实现专门负责某种类型的对象的创建和实例化。客户端代码只需使用工厂接口,并通过依赖注入等方式获取具体的工厂实现对象,即可创建和获取所需的对象实例。

使用工厂模式能够使代码更加灵活、可扩展,并使客户端代码更加简洁易懂,因此在很多框架和开发场景中都广泛应用。

有点啰嗦,简单来说:工厂负责对象的创建,客户端不再关心对象是怎么创建的了,将变化控制在工厂端。

Q.2 这种设计模式有哪几种形式

A.2

工厂模式一般可以分为三种形式:简单工厂模式、工厂方法模式和抽象工厂模式。

  1. 简单工厂模式:也叫静态工厂模式,由一个工厂类根据传入的参数决定创建哪一种产品类的实例。它由一个具体工厂类来创建产品,而这些产品往往都具有共同的父类。简单工厂模式一般只有一个工厂类,且该工厂类的方法一般是静态的。相对于其他工厂模式,简单工厂模式的实现比较简单,并且能够实现简单的对象创建和管理。

  2. 工厂方法模式:也叫多态工厂模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式能够更加灵活地管理对象的创建,而且能够支持多种对象的创建方式。它将创建过程交给子类去实现,使得工厂方法和产品类之间的耦合度更加低,同时也更容易扩展和维护。

  3. 抽象工厂模式:也叫工具箱,提供了一种将多个工厂方法组合在一起使用的方式,它提供了一种抽象工厂来创建一系列相关或相互依赖的对象。抽象工厂模式可以帮助我们实现产品族的概念,即一组相关或相互依赖的产品组成的一个家族。它将同族产品的创建交给一组相关或相互依赖的工厂方法来实现,从而实现同族产品的风格统一和工艺相近。

产品族:我理解像小米手机、音箱、耳机就属于同一个产品族。它们相关在哪里呢?应该是都属于小米这个牌子。

Q.3 使用c++写一个简单工厂的例子

A.3

下面是一个使用 C++ 语言实现简单工厂模式的示例:

#include <iostream>
using namespace std;

// 抽象产品类
class Product {
public:
    virtual void Show() = 0;
};

// 具体产品类A
class ProductA : public Product {
public:
    void Show() {
        cout << "Product A" << endl;
    }
};

// 具体产品类B
class ProductB : public Product {
public:
    void Show() {
        cout << "Product B" << endl;
    }
};

// 简单工厂类
class SimpleFactory {
public:
    static Product* CreateProduct(char type) {
        switch (type) {
            case 'A':
                return new ProductA();
            case 'B':
                return new ProductB();
            default:
                return nullptr;
        }
    }
};

int main() {
    // 通过简单工厂类获取产品实例
    Product* productA = SimpleFactory::CreateProduct('A');
    productA->Show();

    Product* productB = SimpleFactory::CreateProduct('B');
    productB->Show();

    return 0;
}

在上面的示例中,我们定义了一个抽象产品类 Product 和两个具体产品类 ProductAProductB,以及一个简单工厂类 SimpleFactory。在简单工厂类中,我们定义了一个静态方法 CreateProduct,根据传入的参数类型返回相应的产品实例。

在主函数中,我们通过调用简单工厂类的静态方法来获取指定类型的产品实例,并调用其 Show() 方法展示产品信息。

静态工厂根据传入的参数,来判断需要创建的产品实例。有一个明显的缺点,当新增产品时,要新增 if 分支,违反了开闭原则。
另外,这个例子是挺好理解,但是不够具体,所以我希望换个具体的例子。

Q.4 我希望例子更贴近生活一些,你这个有点抽象

A.4

好的,让我们假设有一个宠物店,我们需要根据客户的需求提供不同种类的宠物,例如猫、狗等。我们可以使用简单工厂模式来实现宠物的创建。

以下是使用 C++ 语言实现简单工厂模式的宠物店示例:

#include <iostream>
using namespace std;

// 宠物类抽象基类
class Pet {
public:
    virtual void Show() = 0;
};

// 猫类
class Cat : public Pet {
public:
    void Show() {
        cout << "我是一只猫" << endl;
    }
};

// 狗类
class Dog : public Pet {
public:
    void Show() {
        cout << "我是一只狗" << endl;
    }
};

// 简单工厂类
class PetFactory {
public:
    static Pet* CreatePet(char type) {
        switch (type) {
            case 'C':
                return new Cat();
            case 'D':
                return new Dog();
            default:
                return nullptr;
        }
    }
};

int main() {
    // 通过简单工厂类获取猫和狗的实例
    Pet* cat = PetFactory::CreatePet('C');
    cat->Show();

    Pet* dog = PetFactory::CreatePet('D');
    dog->Show();

    return 0;
}

在上面的示例中,我们定义了一个抽象基类 Pet,以及两个具体子类 CatDog。我们还定义了一个简单工厂类 PetFactory,其中 CreatePet() 方法根据传入的参数类型返回相应的实例。在主函数中,我们通过调用简单工厂类的静态方法来获取指定类型的宠物实例,并调用其 Show() 方法展示宠物信息。

以上代码演示了利用简单工厂模式根据客户的需求来创建不同种类的宠物,客户只需要告诉我们希望获取哪种类型的宠物,我们就可以提供相应的实例。

Q.5 这个例子很好,继续使用这个例子,写一下工厂方法模式的代码

A.5

好的,下面是使用工厂方法模式实现宠物店的示例代码:

#include <iostream>
using namespace std;

// 抽象基类
class Pet {
public:
    virtual void Show() = 0;
};

// 猫类
class Cat : public Pet {
public:
    void Show() {
        cout << "我是一只猫" << endl;
    }
};

// 狗类
class Dog : public Pet {
public:
    void Show() {
        cout << "我是一只狗" << endl;
    }
};

// 宠物工厂抽象基类
class PetFactory {
public:
    virtual Pet* CreatePet() = 0;
};

// 猫工厂类
class CatFactory : public PetFactory {
public:
    Pet* CreatePet() {
        return new Cat();
    }
};

// 狗工厂类
class DogFactory : public PetFactory {
public:
    Pet* CreatePet() {
        return new Dog();
    }
};

int main() {
    // 通过具体工厂类获取猫和狗的实例
    PetFactory* factory1 = new CatFactory();
    Pet* cat = factory1->CreatePet();
    cat->Show();

    PetFactory* factory2 = new DogFactory();
    Pet* dog = factory2->CreatePet();
    dog->Show();

    return 0;
}

在上面的代码中,我们定义了一个 Pet 抽象基类、两个具体子类 CatDog,然后我们将宠物工厂抽象成了一个 PetFactory 基类,并将猫工厂类和狗工厂类继承自 PetFactory,每个工厂类都实现了 CreatePet() 方法来生产具体的宠物

在主函数中,我们使用 PetFactory 的具体实现类(即 CatFactoryDogFactory)来创建对应的宠物实例。由于我们使用了工厂方法模式,所以客户端代码只需要知道具体的工厂类,而不需要直接调用单独的 CreatePet() 方法或者宠物类的构造函数,从而实现了更好的解耦,也方便了代码的维护和扩展。

简单工厂是将所有宠物的生产放到一个工厂中,而工厂方法为每一种宠物单独创建了一个工厂类(狗工厂和猫工厂)。现在客户端只需要在创建工厂之后,直接调用 CreatePet() 方法,就能生产出工厂对应的宠物了,而不再像之前那样需要传入宠物类型参数。
但是缺点也很明显,每增加一种宠物,就要增加一个工厂类。当宠物类过多时,该缺点更明显,这怎么解决呢,我们接着看一下抽象工厂方法,或许能找到答案。

Q.6 好,继续使用这个例子,实现一下抽象工厂模式

A.6

好的,下面是使用抽象工厂模式实现宠物店的示例代码:

#include <iostream>
using namespace std;

// 抽象基类
class Pet {
public:
    virtual void Show() = 0;
};

// 猫类
class Cat : public Pet {
public:
    void Show() {
        cout << "我是一只猫" << endl;
    }
};

// 狗类
class Dog : public Pet {
public:
    void Show() {
        cout << "我是一只狗" << endl;
    }
};

// 猫食品抽象基类
class CatFood {
public:
    virtual void Show() = 0;
};

// 狗食品抽象基类
class DogFood {
public:
    virtual void Show() = 0;
};

// 宠物工厂方法抽象基类
class PetFactory {
public:
    virtual Pet* CreatePet() = 0;
    virtual CatFood* CreateCatFood() = 0;
    virtual DogFood* CreateDogFood() = 0;
};

// 猫工厂方法类
class CatFactory : public PetFactory {
public:
    Pet* CreatePet() {
        return new Cat();
    }

    CatFood* CreateCatFood() {
        return new CatFood();
    }

    DogFood* CreateDogFood() {
        return nullptr;
    }
};

// 狗工厂方法类
class DogFactory : public PetFactory {
public:
    Pet* CreatePet() {
        return new Dog();
    }

    CatFood* CreateCatFood() {
        return nullptr;
    }

    DogFood* CreateDogFood() {
        return new DogFood();
    }
};

// 猫食品类
class CatFoodA : public CatFood {
public:
    void Show() {
        cout << "我是猫食品A" << endl;
    }
};

// 狗食品类
class DogFoodB : public DogFood {
public:
    void Show() {
        cout << "我是狗食品B" << endl;
    }
};

int main() {
    // 通过具体工厂方法类获取对应的宠物和食品实例
    PetFactory* factory1 = new CatFactory();
    Pet* cat = factory1->CreatePet();
    cat->Show();
    CatFood* catFood = factory1->CreateCatFood();
    catFood->Show();

    PetFactory* factory2 = new DogFactory();
    Pet* dog = factory2->CreatePet();
    dog->Show();
    DogFood* dogFood = factory2->CreateDogFood();
    dogFood->Show();

    return 0;
}

在上面的代码中,我们在工厂方法中添加了创建猫食品和狗食品的方法。我们还定义了一个 CatFood 抽象类和一个 DogFood 抽象类,以及它们各自的具体子类 CatFoodADogFoodB

通过这种方式,我们可以将同属于一个产品族的产品创建进行统一管理。在主函数中,我们使用 PetFactory 的具体实现类(即 CatFactoryDogFactory)来创建对应的宠物和食品的实例,从而实现了同属于一个产品族的产品创建统一管理的目的。

猫食品和狗视频居然有各自的抽象基类,而且在 PetFactory 这个抽象基类中,同时存在着 CreateCatFood 和 CreateDogFood 这两个方法,我是很惊讶的。
当我看到它说“将同属于一个产品族的产品创建进行统一管理”时,我明白了过来。它应该是将狗食品、猫食品、宠物当做了一个级别的了,认为这三者属于一个产品族,但其实狗食品和猫食品都属于宠物食品,它们无法和宠物相提并论。
但这只是我的猜测,为了证实这一点,我向 AI 做出来试探。

Q.7 有个疑问,CreateCatFood 和 CreateDogFood 这两个方法是不是统一为 CreateFood 更好

A.7

确实,如果我们只需要生产一种食品,我们可以将 CreateCatFood()CreateDogFood() 方法统一为 CreateFood() 方法,代码就可以变得更加简洁和易于维护。但是,抽象工厂模式的设计初衷是用于创建多个产品族,即多个相关联的产品群,而不仅仅是一个产品类,这样可以更好地实现产品族之间的解耦和扩展性。因此,当生产的产品数量增多时,抽象工厂模式通常会更加实用和合理。在这个例子中,我们只提供了两种不同的食品,可能不足以体现抽象工厂模式的优势,但是在实际的项目中,往往存在更多的产品族和相关联的产品群,这时抽象工厂模式的优势就会更加显著。

确实,它认为狗粮、猫粮、宠物是一个产品族的,看起来 AI 还是有点傻。我们可以说宠物、宠物食品是一个产品族,甚至可以把狗粮、猫粮、狗、猫一起看做一个产品族,但像它这样划分肯定是四不像的。

Q.8 我理解的,狗工厂和猫工厂是两个工厂,狗、狗粮是一个产品族,狗粮和猫粮并不是一个产品族

A.8

是的,你理解得很对。在抽象工厂模式中,一个工厂是负责生产一个产品族(产品群),并且每个产品族中的产品类是相互关联的,但不同产品族之间的产品类是没有关联的,因此我们需要为每个产品族分别创建一个工厂。在这个宠物店的例子中,狗工厂和猫工厂就是两个工厂,分别负责生产狗和猫两种宠物,而狗粮和猫粮并不是同一个产品族,因此它们并不在同一个工厂中,而是分别在狗产品族和猫产品族中,所以我们需要为它们各自创建一个工厂方法,由它们的具体实现类分别来产生狗粮和猫粮的实例。

我测试的这个 AI 就是这样,你说啥,它都说对对对、是是是,附和你,谄媚至极。
它在这里提到了一个产品族中的产品是相互关联的,狗和狗粮关联,猫和猫粮有关联。

Q.9 那既然如此,CreateCatFood 和 CreateDogFood 就应该统一为一个方法 CreateFood ,就像狗和猫的生产那样

A.9

你的理解是正确的,当不同产品族中的产品类之间没有关联时,我们是可以将工厂方法进行简化的,使得每个工厂方法只负责创建一个产品实例。因此,在这个例子中,如果猫粮和狗粮之间是没有任何关联的,我们可以将 PetFactory 中的 CreateCatFood()CreateDogFood() 方法简化为一个 CreateFood() 方法。

示例代码如下:

#include <iostream>
using namespace std;

// 抽象基类
class Pet {
public:
    virtual void Show() = 0;
};

// 猫类
class Cat : public Pet {
public:
    void Show() {
        cout << "我是一只猫" << endl;
    }
};

// 狗类
class Dog : public Pet {
public:
    void Show() {
        cout << "我是一只狗" << endl;
    }
};

// 食品抽象基类
class Food {
public:
    virtual void Show() = 0;
};

// 宠物工厂方法抽象基类
class PetFactory {
public:
    virtual Pet* CreatePet() = 0;
    virtual Food* CreateFood() = 0;
};

// 猫工厂方法类
class CatFactory : public PetFactory {
public:
    Pet* CreatePet() {
        return new Cat();
    }

    Food* CreateFood() {
        return new CatFood();
    }
};

// 狗工厂方法类
class DogFactory : public PetFactory {
public:
    Pet* CreatePet() {
        return new Dog();
    }

    Food* CreateFood() {
        return new DogFood();
    }
};

// 猫食品类
class CatFood : public Food {
public:
    void Show() {
        cout << "我是猫食品" << endl;
    }
};

// 狗食品类
class DogFood : public Food {
public:
    void Show() {
        cout << "我是狗食品" << endl;
    }
};

int main() {
    // 通过具体工厂方法类获取对应的宠物和食品实例
    PetFactory* factory1 = new CatFactory();
    Pet* cat = factory1->CreatePet();
    cat->Show();
    Food* catFood = factory1->CreateFood();
    catFood->Show();

    PetFactory* factory2 = new DogFactory();
    Pet* dog = factory2->CreatePet();
    dog->Show();
    Food* dogFood = factory2->CreateFood();
    dogFood->Show();

    return 0;
}

在上述代码中,我们将 CreateCatFood()CreateDogFood() 方法简化为了一个 CreateFood() 方法。通过这种方式,当不同产品族中的产品类之间没有关联时,我们可以简化工厂方法,这样可以让代码更加简洁易懂。然而,当产品类之间有关联时,我们就必须保留原有的工厂方法,否则会破坏产品之间的完整性。

代码写的符合我要求,但是它为什么说我在做简化呢,我也没有简化啊,每个工厂都能生产一个产品族(宠物和宠物食品),好吧,我认为它说的有道理,只是不适用这个例子。狗粮和猫粮之间到底有没有关联呢?我认为是没有的,狗吃的和猫吃的能有什么联系呢,虽然它们都是宠物食品,但这个关系并不是关联。
我觉得它的抽象工厂例子不太好,想让它换个例子。

Q.10 我还是不太理解你开始为什么要写 CreateCatFood 和CreateDogFood 这两个方法,能换个例子给我讲清楚吗

A.10

当创建的产品有多个组合方式,即每种产品都有不同的变种或者样式时,就需要用到抽象工厂模式来隔离不同的产品族。比如,假设我们在设计一个手机商城网站,需要选择手机品牌和手机配件。为了方便用户购买,我们需要将同一品牌的手机和配件分别显示在一起,保证用户可以轻松购买配件。但是,不同品牌的手机,配件组合方式不同,因此需要为每个品牌创建一个工厂来管理其手机和配件的生产

在这个例子中,我们可以将不同品牌的手机称为“手机产品族”,每个品牌的手机和配件称为“产品群”。因此,我们需要创建一个手机厂商的工厂方法来生产不同品牌的手机和配件

以下是这个例子的示例代码:

#include <iostream>
using namespace std;

// 手机基类
class Phone {
public:
    virtual void Show() = 0;
};

// Apple手机类
class ApplePhone : public Phone {
public:
    void Show() {
        cout << "我是苹果手机" << endl;
    }
};


// 小米手机类
class XiaomiPhone : public Phone {
public:
    void Show() {
        cout << "我是小米手机" << endl;
    }
};

// 手机配件基类
class PhoneAccessory {
public:
    virtual void Show() = 0;
};

// Apple手机配件类
class AppleAccessory : public PhoneAccessory {
public:
    void Show() {
        cout << "我是苹果手机配件" << endl;
    }
};

// 小米手机配件类
class XiaomiAccessory : public PhoneAccessory {
public:
    void Show() {
        cout << "我是小米手机配件" << endl;
    }
};

// 手机工厂方法抽象基类
class PhoneFactory {
public:
    virtual Phone* CreatePhone() = 0;
    virtual PhoneAccessory* CreatePhoneAccessory() = 0;
};

// Apple手机工厂方法类
class ApplePhoneFactory : public PhoneFactory {
public:
    Phone* CreatePhone() {
        return new ApplePhone();
    }

    PhoneAccessory* CreatePhoneAccessory() {
        return new AppleAccessory();
    }
};

// 小米手机工厂方法类
class XiaomiPhoneFactory : public PhoneFactory {
public:
    Phone* CreatePhone() {
        return new XiaomiPhone();
    }

    PhoneAccessory* CreatePhoneAccessory() {
        return new XiaomiAccessory();
    }
};

int main() {
    // 通过具体工厂方法类获取对应的手机和配件实例
    PhoneFactory* appleFactory = new ApplePhoneFactory();
    Phone *applePhone = appleFactory->CreatePhone();
    applePhone->Show();
    PhoneAccessory *appleAccessory = appleFactory->CreatePhoneAccessory();
    appleAccessory->Show();

    PhoneFactory* xiaomiFactory = new XiaomiPhoneFactory();
    Phone *xiaomiPhone = xiaomiFactory->CreatePhone();
    xiaomiPhone->Show();
    PhoneAccessory *xiaomiAccessory = xiaomiFactory->CreatePhoneAccessory();
    xiaomiAccessory->Show();

    return 0;
}

在上述代码中,我们创建了两个不同品牌的手机,每个品牌都有自己的厂商工厂,分别负责生产不同品牌的手机和配件。在具体工厂方法中,我们分别使用 CreatePhone()CreatePhoneAccessory() 方法来创建对应的手机和配件实例。由于不同手机品牌的配件组合方式不同,因此需要为每个品牌分别提供一个对应的工厂方法,而不是将它们合并在一个工厂方法中。

这个例子就跟我想的一样,一个品牌对应一个工厂,生产自家的一系列产品。那我什么宠物那个例子它就始终转不过弯呢?狗牌子和猫牌子按理说好理解的啊,我认为它刚刚改代码并不是真的认为应该那样,只是在迁就我,我再问问看。

Q.11 那我认为你在宠物的例子中犯了错,就像苹果工厂不能生产小米配件一样,狗工厂也不应该能生产猫粮。

A.11

你说得没错,我之前的例子可能不是很妥当,把狗和猫粮放在一个产品族中确实不太合理。在实际开发中,我们在定义不同的抽象工厂时,通常需要把不同的产品分类更加明确,防止不同产品之间的互相混淆。以下是一个更加恰当的例子:

假设我们正在开发一个电子产品商城,我们需要提供两种类型的电子产品:台式机和笔记本。我们还需要为每种电子产品提供两种不同的配件:键盘和鼠标。

在这个例子中,我们可以将不同类型的电子产品称为“电子产品族”,每种电子产品的配件称为“组件”。因此,我们需要创建一个电子产品的工厂方法来生产不同类型的电子产品,以及每种电子产品对应的组件。

下面是一个实现这个例子的抽象工厂模式代码:

#include <iostream>
using namespace std;

// 电子产品基类
class ElectronicProduct {
public:
    virtual void Show() = 0;
};

// 台式机类
class Desktop : public ElectronicProduct {
public:
    void Show() {
        cout << "我是台式机" << endl;
    }
};


// 笔记本类
class Laptop : public ElectronicProduct {
public:
    void Show() {
        cout << "我是笔记本" << endl;
    }
};

// 电子产品组件基类
class ElectronicComponent {
public:
    virtual void Show() = 0;
};

// 键盘类
class Keyboard : public ElectronicComponent {
public:
    void Show() {
        cout << "我是键盘" << endl;
    }
};

// 鼠标类
class Mouse : public ElectronicComponent {
public:
    void Show() {
        cout << "我是鼠标" << endl;
    }
};

// 电子产品工厂方法抽象基类
class ElectronicFactory {
public:
    virtual ElectronicProduct* CreateProduct() = 0;
    virtual ElectronicComponent* CreateComponent() = 0;
};

// 台式机工厂方法类
class DesktopFactory : public ElectronicFactory {
public:
    ElectronicProduct* CreateProduct() {
        return new Desktop();
    }

    ElectronicComponent* CreateComponent() {
        return new Keyboard();
    }
};

// 笔记本工厂方法类
class LaptopFactory : public ElectronicFactory {
public:
    ElectronicProduct* CreateProduct() {
        return new Laptop();
    }

    ElectronicComponent* CreateComponent() {
        return new Mouse();
    }
};

int main() {
    // 通过具体工厂方法类获取对应的电子产品和组件实例
    ElectronicFactory* desktopFactory = new DesktopFactory();
    ElectronicProduct *desktop = desktopFactory->CreateProduct();
    desktop->Show();
    ElectronicComponent *keyboard = desktopFactory->CreateComponent();
    keyboard->Show();

    ElectronicFactory* laptopFactory = new LaptopFactory();
    ElectronicProduct *laptop = laptopFactory->CreateProduct();
    laptop->Show();
    ElectronicComponent *mouse = laptopFactory->CreateComponent();
    mouse->Show();

    return 0;
}

在上述代码中,我们创建了两种不同类型的电子产品,每种类型的电子产品需要提供自己的工厂方法,以及对应的组件。在具体工厂方法中,我们分别使用 CreateProduct()CreateComponent() 方法来创建对应的产品和组件实例。由于不同类型的电子产品的配件组合方式不同,因此需要为每种类型的电子产品分别提供一个对应的工厂方法,而不是将它们合并在一个工厂方法中。

反手就又是一个例子,确实比我效率高,这认错态度也可以。那我就认为你真的知道错误了,哈哈。

Q.12 最后总结下三种工厂模式的优缺点吧

A.12

好的,下面是三种不同的工厂模式的优缺点总结:

  1. 简单工厂模式

简单工厂模式的优点是实现简单易懂,适用于对实例化过程较为简单的类。例如,如果需要根据一些较为简单的条件来创建对象,则使用简单工厂模式可能是一个不错的选择。

缺点是工厂类集成难度较高,如果新添加了一个类,就需要修改工厂类的代码,这违背了开闭原则。因此在类的数量较多或者产品族的类别比较多时,简单工厂模式并不适用。

  1. 工厂方法模式

工厂方法模式的优点是遵循开闭原则,扩展性好,每个产品的具体实现都可以对应一个具体的工厂类进行生产,使系统具有良好的灵活性和可扩展性。

缺点是每个具体产品对应一个具体工厂,类的个数会增加,导致系统中类的个数增加,会增加系统的实现难度和复杂度。

  1. 抽象工厂模式

抽象工厂模式的优点是提供一个接口,用于创建相关联的或者相互依赖的产品族,解决了工厂方法模式中同样的问题,克服了简单工厂模式违背开闭原则的缺点。

缺点是增加类的数量,扩展新的产品结构需要编写新的产品类和新的工厂,因为每个具体工厂只负责创建一种产品结构,难以扩展。同时,由于它的增加新的产品族比较困难,因此不太适用于大型产品族的开发。

Q.13 画一下它们的类图吧

A.13

它不行,显示不了图片,还得靠我自己来啊。

11.1 简单工厂模式类图

在这里插入图片描述

11.2 工厂方法模式类图

在这里插入图片描述

11.3 抽象工厂模式类图

在这里插入图片描述

11.4 再画一下抽象工厂模式的产品族示意图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/655034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作受限的线性表——队列

本文主要内容&#xff1a;介绍了队列的基本概念和基本操作&#xff0c;详细介绍了队列的顺序存储和链式存储。并介绍了循环队列和双端队列&#xff08;以及输入/输出受限的双端队列&#xff09;&#xff0c;及其基本操作。 目录 队列一、队列的基本概念1、基本概念2、基本操作…

计算机视觉-目标检测(二):从R-FCN到YOLO-v3

文章目录 1. R-FCN1.1 动机1.2. R-FCN 网络结构1.3. R-FCN 的损失函数1.4. R-FCN的训练及性能 2. YoLO-v12.1 简介2.2 YOLO-v1网络结构2.3 目标函数2.4 YOLO-v1的优缺点 3. YOLO-v23.1 YOLO-v2相比v1的优化 4. YOLO-v3参考 1. R-FCN 论文链接&#xff1a;R-FCN:Object Detecti…

java格式化数字 NumberFormat及DecimalFormat

一、JavaAPI官方描述 1、NumberFormat NumberFormat帮助您格式化和解析任何区域设置的数字。您的代码可以完全独立于小数点&#xff0c;千位分隔符的区域设置约定&#xff0c;甚至是使用的特定十进制数字&#xff0c;或者数字格式是否为十进制。 2、 DecimalFormat Decimal…

Linux之YUM管理工具

目录 Linux之YUM管理工具 定义 实现YUM的三个机制 RHEL8中yum源变化说明 案例 示例1 --- 建立本地光盘源&#xff08;本地yum源&#xff09; 示例2 --- 配置互联网源 yum(dnf)工具管理软件包 安装软件包 module子命令 案例 yum-config-manager的使用 定义 yum-conf…

Linux系统如何配置网络

Linux系统的三种网络模式&#xff1a; 桥接&#xff1a;可以和外部设备通信&#xff0c;主机和Ubuntu分别使用不同的IP地址NAT&#xff1a;可以和外部设备通信&#xff0c;主机和Ubuntu公用一个IP地址主机&#xff1a;只能和主机通信 在此我们介绍如何配置桥接网络&#xff1…

谓词的介绍与基本使用

&#x1f6a8;谓词 &#x1f6a6;概念 1.返回类型为bool的仿函数 2.接受一个参数—一元谓词 接受一个参数—二元谓词 &#x1f680;1.一元谓词 ⛽使用方法 因为返回值为bool类型&#xff0c;所以经常会将他使用成判断关系的函数 我们使用find_if&#xff08;&#xff09;对…

HBase 2.3.7中snappy压缩配置

本文将介绍如何在HBase 2.3.7中配置snappy压缩。snappy是一种快速的数据压缩和解压缩算法&#xff0c;可以提高HBase的存储空间利用率和读写性能。本文将使用HBase 2.3.7版本&#xff0c;运行在三个Ubuntu系统的虚拟机中&#xff0c;分别作为master和slave节点。 主要步骤如下…

【SpringBoot】SpringBoot Starter 作用及原理

文章目录 前言一、什么是 Starter二、Starter 的作用三、spring 整合组件四、spring-boot 整合组件五、Starter 原理 前言 有没有在入行后直接基于 SpringBoot 开发项目&#xff0c;没有 spring、servlet 开发经历的? 有没有用 SpringBoot 开发项目&#xff0c;但是第一次听…

服务注册中心Eureka

服务注册中心Eureka Eureka介绍Eureka 环境搭建Eureka 集群配置Eureka 的自我保护模式Eureka 架构图 Eureka介绍 在微服务架构中&#xff0c;有着许许多多的微服务&#xff0c;微服务之间需要彼此进行远程调用&#xff0c;需要知道彼此的地址&#xff0c;通过人工的方式去管理…

C++算法:加权连通图的最小生成树(Prim)

文章目录 前言一、Prim算法原理二、算法实现1、生成图2、Prim 总结原创文章&#xff0c;未经许可&#xff0c;严禁转载 前言 在前文加权连通图的最小生成树(Kruskal)中已经用以边找点的方式实现最小生成树的生成。Prim算法也是一种常用的最小生成树算法&#xff0c;和Kruskal不…

python 妙笔生花

1.学习编程好处 最主要的好处就是,思考问题的方式变得更加具有逻辑性。 日常我们敲代码时,需要思考每一行的代码执行效果,它就需要认真设计每行代码可用性。如果在设计上发生错误,在代码执行时就会报错。还能做到 触类旁通。 古语有云: 有道无术,术可求,有术无道,止于术…

armbian可视化查看系统的使用情况

文章目录 armbian查看系统的使用情况在终端可视化查看方式htop简介htop安装和使用的步骤 在浏览器可视化查看方式 armbian查看系统的使用情况 在终端可视化查看方式 htop简介 htop’是一款任务管理器和系统监视工具&#xff0c;可在Armbian Linux中使用。它提供了比默认任务…

Python使用多线程操作tif影像和HBase数据库

本文介绍使用Python的多线程技术&#xff0c;提高happybase模块和gdal模块的效率&#xff0c;从tif格式的影像文件中读取数据&#xff0c;并将其存储到HBase数据库中。主要步骤包括&#xff1a; 准备工作&#xff1a;安装Python环境&#xff0c;安装happybase模块和gdal模块&a…

windows安装jdk1.8

1.下载jdk8 https://www.oracle.com/java/technologies/downloads/#java8-windows 百度网盘&#xff1a; 链接: https://pan.baidu.com/s/1qtVZ3Rsa1_n9XsFcXj07rA 提取码: yhwc 2.双击以后进行JDK的安装 操作前先在D盘保存java文件夹&#xff0c;里面新建jdk1.8.0_241文件…

AntDB 替换某省电信大数据平台的案例分享

亚信自研分布式数据库AntDB落地某省电信的案例分享 整体介绍 某省电信大数据分析平台&#xff0c;需要对BSS的三户、订单、实例等近10TB级的数据进行快速分析统计&#xff0c;每次分析的数据量最高达到5亿级别&#xff0c;同时需要向其它厂商开放这种实时的数据分析能力&…

Java-API简析_java.util.Currency类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/131255544 出自【进步*于辰的博客】 其实我的【Java-API】专栏内的博文对大家来说意义是不大的。…

对象实例化空指针处理

1 问题 如何解决对象实例化空指针异常&#xff1f; 2 方法 首先创建一个package包&#xff0c;将其Menu类及相关代码放入其中&#xff0c;并在该package包下创建另一个类MenuItem&#xff0c;然后通过构造函数&#xff0c;写入需要运行的对象信息&#xff0c;最后在Menu类中用n…

leetcode 151. 反转字符串中的单词

2023.6.14 这道题全面考察了字符串的一些操作&#xff0c;这里我的思路是&#xff1a; 先对字符串进行空格去除操作&#xff0c;这里要注意一个细节&#xff1a;先用for循环去除连续空格&#xff0c;再用if判断开头和结尾的空格。再对没有异常空格的s 做一个反转操作。再对每一…

计算机网络基础知识(九)—— 什么是TelnetS?Telnet Over TLS

文章目录 01 | TelnetS02 | OpenSSL03 | 实现思路服务器处理流程客户端处理流程 04 | 代码实现服务端代码客户端代码编译过程 & 执行结果 前面学习了什么是HTTPS协议&#xff0c;了解了HTTPS的工作原理以及具体的工作流程&#xff0c;了解了HTTP协议和HTTPS协议之间的区别。…

SSM框架搭建

SSM环境搭建 1 IDE的话&#xff0c;我用的MyEcplise&#xff0c;如果用Ecplise的话&#xff0c;需要自行配置服务器。 首先&#xff0c;建一个Dynamic工程&#xff0c;需要注意的是一定要勾选上web.xml。 将Spring框架包、jstl包、standard包、common-logging包、aopallian…