設計模式學習(二)工廠模式——抽象工廠模式+登錄檔

paw5zx發表於2024-07-09

目錄
  • 前言
  • 使用簡單工廠改進
  • 使用登錄檔改進
  • 參考文章

前言

上一篇文章中我們提到了抽象工廠模式初版程式碼的一些缺點:①客戶端違反開閉原則②提供方違反開閉原則。本文將針對這兩點進行討論

使用簡單工廠改進

對於缺點①,我們可以使用簡單工廠的思路來改進抽象工廠的初版程式碼。對於上一篇文章中的例子,我們去除CameraFactoryBaslerCameraFactorySickCameraFactory,取而代之的是SimpleFactory類。

類圖如下:

程式碼如下:

//工廠類
class SimpleFactory
{
public:
    BaslerCamera* CreateBaslerCamera()
    {
        if ("Linux" == os_name_)
        {
            return new LinuxBaslerCamera();
        }
        else if ("Windows" == os_name_)
        {
            return new WindowsBaslerCamera();
        }
        else
        {
            return nullptr;
        }
    }

    SickCamera* CreateSickCamera()
    {
        if ("Linux" == os_name_)
        {
            return new LinuxSickCamera();
        }
        else if ("Windows" == os_name_)
        {
            return new WindowsSickCamera();
        }
        else
        {
            return nullptr;
        }
    }
public:
    std::string os_name_ = "Linux";

};

//客戶端
int main()
{
    SimpleFactory* camera_factory = new SimpleFactory();
   
    BaslerCamera* basler_camera = camera_factory->CreateBaslerCamera();
    basler_camera->OpenCamera();

    SickCamera* sick_camera = camera_factory->CreateSickCamera();
    sick_camera->OpenCamera();

    return 0;
}

注意,上述方法雖然改進了缺點①,但是缺點②仍存在。

使用登錄檔改進

對於缺點②,其本質是:增加新產品時,對工廠類帶來的修改違反了開閉原則。對於這種情況,我們可以參考《設計模式學習(二)工廠模式——工廠方法模式+登錄檔》中提到的登錄檔,來去除switchif這種分支判斷,解除分支判斷帶來的耦合。

對於具體產品,我們可以這樣將它註冊:

class LinuxBaslerCamera : public BaslerCamera
{
public:
    ~LinuxBaslerCamera() override = default;
    bool OpenCamera() override
    {
        return true;
    }
};

ReflectRegister("LinuxBasler", LinuxBaslerCamera);

然後工廠類的程式碼可以簡化為:

class SimpleFactory
{
public:
    BaslerCamera* CreateBaslerCamera()
    {
        std::string name = os_name_ + "Basler";
        return Object::CreateObject<BaslerCamera>(name);
    }

    SickCamera* CreateSickCamera()
    {
        std::string name = os_name_ + "Sick";
        return Object::CreateObject<SickCamera>(name);
    }
public:
    std::string os_name_ = "Linux";
};

這樣,在產品族增加時(比如增加一個HarmonyOS),我們只需要在它下面的產品類對應的檔案中使用ReflectRegister註冊,然後改變os_name_即可(當然os_name_也可以在執行時從配置檔案中載入,這樣更好)。

而對於現有的產品族內增加新產品(比如增加一個Huaray相機),工廠類中還是要增加一個CreateHuarayCamera函式。

參考文章

1.《大話設計模式》

相關文章