【问题标题】:What is the difference between Factory method design pattern and Bridge pattern?工厂方法设计模式和桥接模式有什么区别?
【发布时间】:2019-08-01 11:08:16
【问题描述】:

大家好,

谁能解释一下工厂方法设计模式和桥接模式之间的区别?

因为据我了解,这两种设计模式都用于分离接口和实现:

将抽象与实现分离。抽象将客户端代码与实现分开。因此,可以在不影响客户端代码的情况下更改实现,并且在实现更改时无需编译客户端代码。

工厂方法:

没有工厂方法的问题:

在某些情况下,我们有一个包含一些类的库来实现客户端业务逻辑。我们从客户端应用程序创建库类的对象来完成任务。

但有时,根据客户对合并额外功能的要求,我们可能需要在库中添加额外的类。然后我们需要在客户端应用程序中创建新类的对象。

因此,每次在库端进行新的更改时,客户端都需要在其末尾进行一些相应的更改并重新编译代码。

使用工厂方法:

为了避免这个问题,我们使用工厂方法将对象创建与客户端应用程序分离。客户端只需要调用库的工厂方法,无需担心对象创建的实际实现。

所以我们创建工厂方法来创建对象并将其移动到单独的实现文件中。 现在实现文件是唯一需要派生类知识的文件。因此,如果对任何派生类进行更改或添加任何新类,则实现文件是唯一需要重新编译的文件。使用工厂的每个人都只会关心接口,它应该在应用程序的整个生命周期中保持一致。

客户端应用交互->工厂方法和调用-->实现

如果我采用下面的示例程序,在添加任何类或对类进行任何更改后,仅重新编译 Vehicle.cpp 文件就足够了吗? 还有在创建工厂方法的时候,我们使用静态方法吗?

Vehicle.h

#include <iostream> 
using namespace std; 

enum VehicleType { 
    VT_TwoWheeler,    VT_ThreeWheeler,    VT_FourWheeler 
}; 

// Library classes 
class Vehicle { 
public: 
    virtual void printVehicle() = 0; 
    static Vehicle* Create(VehicleType type); 
}; 
class TwoWheeler : public Vehicle { 
public: 
    void printVehicle() { 
        cout << "I am two wheeler" << endl; 
    } 
}; 
class ThreeWheeler : public Vehicle { 
public: 
    void printVehicle() { 
        cout << "I am three wheeler" << endl; 
    } 
}; 
class FourWheeler : public Vehicle { 
    public: 
    void printVehicle() { 
        cout << "I am four wheeler" << endl; 
    } 
}; 

Vehicle.cpp(实施文件)

// Factory method to create objects of different types. 
// Change is required only in this function to create a new object type 
Vehicle* Vehicle::Create(VehicleType type) { 
    if (type == VT_TwoWheeler) 
        return new TwoWheeler(); 
    else if (type == VT_ThreeWheeler) 
        return new ThreeWheeler(); 
    else if (type == VT_FourWheeler) 
        return new FourWheeler(); 
    else return NULL; 
} 

Client.h 文件

// Client class 
class Client { 
public: 

    // Client doesn't explicitly create objects 
    // but passes type to factory method "Create()" 
    Client() 
    { 
        VehicleType type = VT_ThreeWheeler; 
        pVehicle = Vehicle::Create(type); 
    } 
    ~Client() { 
        if (pVehicle) { 
            delete[] pVehicle; 
            pVehicle = NULL; 
        } 
    } 
    Vehicle* getVehicle()  { 
        return pVehicle; 
    } 

private: 
    Vehicle *pVehicle; 
}; 

// Driver program 

int main() { 
    Client *pClient = new Client(); 
    Vehicle * pVehicle = pClient->getVehicle(); 
    pVehicle->printVehicle(); 
    return 0; 
}

请提供您对此的看法。

提前致谢。

【问题讨论】:

  • 桥接模式是一种结构模式。它将接口与实现分开。工厂方法是一种创建模式。它负责创建对象的实例。
  • "只重新编译Vehicle.cpp文件就够了吗?"你试过了吗?我会说这已经足够了。
  • "我们使用静态方法吗?"是的,否则,您将需要一个 Vehicle 实例来调用 Create。
  • delete[] 在这里是错误的。安全的是从Create返回unique_ptr

标签: c++ algorithm design-patterns


【解决方案1】:

工厂方法是关于创建对象的灵活性,可以创建新对象,在创建基本代码时是未知的。例如,假设您正在为 IO 卡设计接口包装器以与您的项目集成。你从 Decklink 卡和 Bluefish 卡开始。稍后您想在不修改任何过去代码的情况下添加 Matrox 卡,工厂模式将助您一臂之力。

桥接模式更多的是关于将接口与实现分离(隐藏复杂的代码)。

在您的代码中加入:假设您要添加 VT_FiveWheeler - 您必须修改 Vehicle.h 以添加枚举 VehicleType(听起来很糟糕)。 Create Method 可以是静态的,也可以是一个简单的辅助函数,如下所示:

namespace Vehicle {
    class Vehicle {
    public:
        virtual void printVehicle() = 0;
    };
}

namespace Vehicle {
    namespace TwoWheeler {

        class TwoWheeler : public Vehicle {
        public:
            void printVehicle() {
                cout << "I am two wheeler" << endl;
            }
        };
        shared_ptr<Vehicle> create() { return make_shared<TwoWheeler>(); }
    }
}

namespace Vehicle {
    namespace ThreeWheeler {
        class ThreeWheeler : public Vehicle {
        public:
            void printVehicle() {
                cout << "I am three wheeler" << endl;
            }
        };
        shared_ptr<Vehicle> create() { return make_shared<ThreeWheeler>(); }
    }
}

namespace Vehicle {
    class factory
    {
        typedef function<shared_ptr<Vehicle>(void) > func_t;

    public:

        //register a vehicle
        void register_vehicle(const string& name, func_t func)
        {
            registered_vehicles_.insert(make_pair(name, func));
        }

        //to create a vehicle
        shared_ptr<Vehicle> create_vehicle(string name)
        {
            return registered_vehicles_[name]();
        }

        map<string, func_t> get() { return registered_vehicles_;  }

    private:
        map<string, func_t> registered_vehicles_;
    };
}

Vehicle::factory my_vehicle_factory;


int main() {

    //register the vehicle in the factory first
    my_vehicle_factory.register_vehicle("TwoWheeler", Vehicle::TwoWheeler::create);

    auto p1 = my_vehicle_factory.create_vehicle("TwoWheeler");
    auto p2 = my_vehicle_factory.create_vehicle("TwoWheeler");

    // A new vehicle has arrived, so first registered it
    my_vehicle_factory.register_vehicle("ThreeWheeler", Vehicle::ThreeWheeler::create);
    auto p3 = my_vehicle_factory.create_vehicle("ThreeWheeler");


    p1->printVehicle();
    p2->printVehicle();
    p3->printVehicle();
}

【讨论】:

  • 非常感谢您的详细解释。作为初学者,很高兴我看到了一些高级 C++ 概念,例如命名空间、智能指针 (shared_ptr)、STL (maps)。如果您能解释使用它们的必要性以及它们在这种情况下如何工作,那将是非常好的?在这里,在代码中没有命名冲突。那么使用“命名空间”的必要性是什么?使用“命名空间”有什么原因吗?为什么我们使用 shared_ptr?提供共享所有权的必要性是什么?
  • 还有为什么我们要在类外声明 shared_ptr ? “shared_ptr create() { return make_shared(); }” 以及为什么我们声明“Vehicle::factory my_vehicle_factory;”在命名空间之外?最后为什么我们在这里使用地图?
  • 所有的车辆对象构造都是相互独立的,为了在创建过程中保持对称性,它们使用单​​个辅助函数 namecreate() 创建,但由命名空间分隔以避免冲突。
  • 这里使用std::map来简化新车的注册。多态性是使用指针实现的,shared_ptr 优于原始指针。您可以使用静态成员函数代替辅助函数。想展示一个桥接模式的工作示例,但答案很短。
猜你喜欢
  • 2015-12-28
  • 1970-01-01
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
  • 2010-10-02
  • 2010-10-11
  • 1970-01-01
  • 2016-09-29
相关资源
最近更新 更多