Abstract Factory Pattern with Registry Implementation

Improving Abstract Factory with Simple Factory

The initial implementation of abstract factory pattern presents two major issues: client code violates the open-closed principle, and provider code also breaches this principle. To address the first issue, we can apply simple factory concepts to refactor the abstract factory approach.

Instead of maintaining separate factory classes like CameraFactory, BaslerCameraFactory, and SickCameraFactory, we introduce a unified SimpleFactory class.

// Factory implementation
class SimpleFactory
{
public:
    BaslerCamera* CreateBaslerCamera()
    {
        if ("Linux" == platform_)
        {
            return new LinuxBaslerCamera();
        }
        else if ("Windows" == platform_)
        {
            return new WindowsBaslerCamera();
        }
        else
        {
            return nullptr;
        }
    }

    SickCamera* CreateSickCamera()
    {
        if ("Linux" == platform_)
        {
            return new LinuxSickCamera();
        }
        else if ("Windows" == platform_)
        {
            return new WindowsSickCamera();
        }
        else
        {
            return nullptr;
        }
    }

    std::string platform_ = "Linux";
};

// Client usage
int main()
{
    SimpleFactory* factory = new SimpleFactory();
   
    BaslerCamera* basler = factory->CreateBaslerCamera();
    basler->OpenCamera();

    SickCamera* sick = factory->CreateSickCamera();
    sick->OpenCamera();

    return 0;
}

While this approach resolves the client-side violation, the provider-side issue persists.

Registry-Based Enhancement

The core problem with provider code is that adding new products requires modifications to the factory class, violating the open-closed principle. To eliminate the conditional branching logic and reduce coupling, we can implement a registry mechanism similar to what's used in factory method patterns.

Product registration can be implemented as follows:

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

ReflectRegister("LinuxBasler", LinuxBaslerCamera);

With the registry in place, the factory implementation becomes:

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

    SickCamera* CreateSickCamera()
    {
        std::string identifier = platform_ + "Sick";
        return Object::CreateObject<SickCamera>(identifier);
    }

    std::string platform_ = "Linux";
};

When extending to new product families like HarmonyOS, simply register the corresponding product classes using ReflectRegister and udpate the platform_ value. Ideally, this platform identifier should be loaded dynamically from configuration files at runtime.

However, when adding new products within existing families (such as introducing a Huaray camera), the factory class still requires a new creation method like CreateHuarayCamera().

Tags: design-patterns abstract-factory factory-method registry-pattern cpp

Posted on Fri, 29 May 2026 23:34:17 +0000 by micheal_newby