设计模式-创建型模式之-抽象工厂模式

动机

在之前介绍工厂模式时,我们以播放器为例,该播放器支持多种多媒体处理库,如 ffmpeggstreamer。实际上,这两个多媒体库不仅支持视频播放,还支持音频播放。那么,我们是否需要再用工厂模式重新设计一套音频播放器呢?答案是否定的。当产品类存在两个维度的划分,播放器这个例子中即 库类类型播放器类型 时,使用抽象工厂模式会更为合适。

定义

抽象工厂模式是一种为访问类提供创建一组相关或相互依赖对象的接口的设计模式。在这种模式下,访问类无需指定具体产品类,就能获取同族的不同等级的产品。与工厂模式类似,抽象工厂模式也包含四种角色:

  • 抽象工厂角色(Creator):这是一个接口,所有具体工厂都需要实现该接口。
  • 具体工厂角色(Concrete Creator):负责实例化具体的产品对象。
  • 抽象产品角色(Product):如同简单工厂模式一样,它是工厂类所创建的所有实例的类的共同基类,用于描述产品的公共接口。
  • 具体产品角色(Concrete Product):即具体工厂类需要实例化的对象。

为了更好地理解抽象工厂模式,我们可以看看具体产品角色的划分。例如,有 ffmpeg 的音频播放器ffmpeg 的视频播放器gstreamer 的音频播放器gstreamer 的视频播放器,这里的两个维度分别是 库类类型播放器类型。而抽象产品角色,无论是音频播放器还是视频播放器,都可以抽象出相同的方法。抽象工厂角色则需要实现多个创建接口,对应播放器类型这个维度,比如音频播放器创建接口和视频播放器创建接口,具体工厂角色需要分别实现这些接口。

下面我们通过一个具体的例子来加深理解。

示例

首先,对于抽象产品类,无论是音频播放器还是视频播放器,都具备播放和停止等基本操作,因此其定义基本保持不变。

class PlayerInterface
{
public:
    virtual ~PlayerInterface()
    {
        std::cout << "~PlayerInterface()" << std::endl;
    }

    virtual void play() = 0;
    virtual void stop() = 0;
};

接下来,我们基于 ffmpeg 和 gstreamer 分别实现音频播放器和视频播放器。

// ffmpeg 的视频播放器实现
class FfmpegVideoPlayer : public PlayerInterface
{
public:
    void play() override
    {
        std::cout << "ffmpeg video play" << std::endl;
    }

    void stop() override
    {
        std::cout << "ffmpeg video stop" << std::endl;
    }
};

// ffmpeg 的音频播放器实现
class FfmpegAudioPlayer : public PlayerInterface
{
public:
    void play() override
    {
        std::cout << "ffmpeg audio play" << std::endl;
    }

    void stop() override
    {
        std::cout << "ffmpeg audio stop" << std::endl;
    }
};

// gstreamer 的视频播放器实现
class GstreamerVideoPlayer : public PlayerInterface
{
public:
    void play() override
    {
        std::cout << "gstreamer video play" << std::endl;
    }

    void stop() override
    {
        std::cout << "gstreamer video stop" << std::endl;
    }
};

// gstreamer 的音频播放器实现
class GstreamerAudioPlayer : public PlayerInterface
{
public:
    void play() override
    {
        std::cout << "gstreamer audio play" << std::endl;
    }

    void stop() override
    {
        std::cout << "gstreamer audio stop" << std::endl;
    }
};

抽象工厂类也需要相应地进行改变,以便根据需求创建音频或视频播放器。这里我们可能会考虑将其统一为一个接口,并通过指定参数来决定创建音频播放器还是视频播放器,但这样做会存在与简单工厂模式类似的问题。例如,如果后续需要新增一个图片播放器,就会破坏开闭原则。当然,如果播放器类型是有限的,并且已经全部考虑周全,这种方式也是可行的。

class CreatorInterface
{
public:
    virtual PlayerInterface *create_Vplayer() = 0;
    virtual PlayerInterface *create_Aplayer() = 0;
};

接下来,我们分别实现 ffmpeg 和 gstreamer 的创建类,它们都支持创建音频播放器和视频播放器。

class FfmpegCreator : public CreatorInterface
{
public:
    PlayerInterface *create_Vplayer() override
    {
        return new FfmpegVideoPlayer();
    }

    PlayerInterface *create_Aplayer() override
    {
        return new FfmpegAudioPlayer();
    }
};

class GstreamerCreator : public CreatorInterface
{
public:
    PlayerInterface *create_Vplayer() override
    {
        return new GstreamerVideoPlayer();
    }

    PlayerInterface *create_Aplayer() override
    {
        return new GstreamerAudioPlayer();
    }
};

使用抽象工厂模式非常方便,你只需要指定想要基于哪种库实现的哪种播放器即可。

int main()
{
    CreatorInterface *creator;
    PlayerInterface *player;

    creator = new FfmpegCreator();
    player = creator->create_Vplayer();
    player->play();
    player->stop();
    delete player;
    delete creator;

    creator = new GstreamerCreator();
    player = creator->create_Aplayer();
    player->play();
    player->stop();
    delete player;
    delete creator;
    return 0;
}

通过上述示例,我们可以看到抽象工厂模式在处理具有多个维度的产品创建时的灵活性和可扩展性。它能够有效地将对象的创建和使用分离,提高代码的可维护性和可复用性。

posted @ 2025-06-11 17:02  thammer  阅读(13)  评论(0)    收藏  举报