工厂方法(Factory Method)模式
解决的问题
工厂方法模式是为了解决对象创建的问题。它提供了一种将对象创建的逻辑与使用分离的方式,使得系统在不修改已有代码的情况下可以扩展新的产品类型。具体来说,工厂方法模式允许一个类的实例化延迟到其子类,从而使得系统更加灵活和可扩展。
适用场景
- 当一个类无法预知它需要创建的对象的类时。
- 当一个类希望它的子类来指定它所创建的对象时。
- 当类将责任委托给多个帮助子类中的一个,并且希望将哪一个帮助子类是代理者这一信息局部化时。
参与者角色
- Product:定义工厂方法所创建的对象的接口。
- ConcreteProduct:实现
Product
接口的具体产品类。 - Creator:声明工厂方法,该方法返回一个
Product
类型的对象。Creator
也可以定义一个工厂方法的默认实现,返回一个默认的ConcreteProduct
。 - ConcreteCreator:重写工厂方法以返回一个
ConcreteProduct
的实例。
GUI视图创建示例
假设我们有一个CAD模型,我们希望为这个模型创建不同的视图,比如表格视图(TableView
)和图形视图(GraphicsView
)。我们可以使用工厂方法模式来实现这一需求。
代码示例
#include <iostream>
#include <string>
#include <memory>
// 产品接口
class View {
public:
virtual ~View() {}
virtual void show() const = 0;
};
// 具体产品1:表格视图
class TableView : public View {
public:
void show() const override {
std::cout << "Showing Table View" << std::endl;
}
};
// 具体产品2:图形视图
class GraphicsView : public View {
public:
void show() const override {
std::cout << "Showing Graphics View" << std::endl;
}
};
// 抽象创建者
class ViewCreator {
public:
virtual ~ViewCreator() {}
virtual std::unique_ptr<View> createView() const = 0;
void displayView() const {
std::unique_ptr<View> view = createView();
view->show();
}
};
// 具体创建者1:表格视图创建者
class TableViewCreator : public ViewCreator {
public:
std::unique_ptr<View> createView() const override {
return std::make_unique<TableView>();
}
};
// 具体创建者2:图形视图创建者
class GraphicsViewCreator : public ViewCreator {
public:
std::unique_ptr<View> createView() const override {
return std::make_unique<GraphicsView>();
}
};
// 客户端代码
int main() {
// 创建表格视图
std::unique_ptr<ViewCreator> tableViewCreator = std::make_unique<TableViewCreator>();
tableViewCreator->displayView();
// 创建图形视图
std::unique_ptr<ViewCreator> graphicsViewCreator = std::make_unique<GraphicsViewCreator>();
graphicsViewCreator->displayView();
return 0;
}
代码说明
产品接口 (View
)
- View:定义了视图的接口,所有视图类都必须实现
show()
方法。
具体产品 (TableView
和 GraphicsView
)
- TableView:实现了
View
接口,具体展示了表格视图。 - GraphicsView:实现了
View
接口,具体展示了图形视图。
抽象创建者 (ViewCreator
)
- ViewCreator:声明了工厂方法
createView()
,该方法返回一个View
类型的对象。还定义了一个displayView()
方法,用于展示视图。
具体创建者 (TableViewCreator
和 GraphicsViewCreator
)
- TableViewCreator:重写了
createView()
方法,返回一个TableView
对象。 - GraphicsViewCreator:重写了
createView()
方法,返回一个GraphicsView
对象。
客户端代码
- main():客户端代码通过创建具体的创建者对象,调用
displayView()
方法来展示不同的视图。
总结
工厂方法模式通过将对象的创建延迟到子类来实现了灵活的对象创建机制。在GUI视图创建的示例中,工厂方法模式允许我们为同一CAD模型创建不同的视图(表格视图和图形视图),并且可以在不修改已有代码的情况下扩展新的视图类型。
C++ Template 与 Factory Method 模式的比较
1. 目的与适用场景
Factory Method 模式:
- 目的:Factory Method 模式是一种创建型设计模式,旨在将对象的创建过程与使用分离,使得系统更加灵活和可扩展。
- 适用场景:适用于需要根据不同的条件创建不同类型的对象,而不希望将这些条件直接暴露给客户端代码的场景。
C++ Template:
- 目的:C++ Template 是一种泛型编程机制,旨在提供一种编写通用代码的方式,使得代码可以在编译时进行类型参数化。
- 适用场景:适用于需要编写通用算法或数据结构,能够在编译时针对不同的数据类型进行实例化的场景。
2. 实现机制
Factory Method 模式:
- 实现机制:通过定义一个抽象的工厂接口(Creator),具体的工厂类(ConcreteCreator)实现这个接口,并负责创建具体的产品对象(ConcreteProduct)。
- 优点:提供了运行时的灵活性,可以在不修改客户端代码的情况下扩展新的产品类型。
- 缺点:需要编写多个类和接口,代码量较大。
C++ Template:
- 实现机制:通过模板参数化类型,使得编写的代码可以适用于不同的数据类型,编译器在编译时生成具体的代码实例。
- 优点:提供了编译时的类型安全性和性能优化,减少了运行时开销。
- 缺点:模板代码的错误信息通常较为复杂,不易调试。
3. 代码示例
Factory Method 模式:
#include <iostream>
#include <memory>
// 产品接口
class View {
public:
virtual ~View() {}
virtual void show() const = 0;
};
// 具体产品1:表格视图
class TableView : public View {
public:
void show() const override {
std::cout << "Showing Table View" << std::endl;
}
};
// 具体产品2:图形视图
class GraphicsView : public View {
public:
void show() const override {
std::cout << "Showing Graphics View" << std::endl;
}
};
// 抽象创建者
class ViewCreator {
public:
virtual ~ViewCreator() {}
virtual std::unique_ptr<View> createView() const = 0;
void displayView() const {
std::unique_ptr<View> view = createView();
view->show();
}
};
// 具体创建者1:表格视图创建者
class TableViewCreator : public ViewCreator {
public:
std::unique_ptr<View> createView() const override {
return std::make_unique<TableView>();
}
};
// 具体创建者2:图形视图创建者
class GraphicsViewCreator : public ViewCreator {
public:
std::unique_ptr<View> createView() const override {
return std::make_unique<GraphicsView>();
}
};
// 客户端代码
int main() {
// 创建表格视图
std::unique_ptr<ViewCreator> tableViewCreator = std::make_unique<TableViewCreator>();
tableViewCreator->displayView();
// 创建图形视图
std::unique_ptr<ViewCreator> graphicsViewCreator = std::make_unique<GraphicsViewCreator>();
graphicsViewCreator->displayView();
return 0;
}
C++ Template:
#include <iostream>
// 模板类,表示视图
template <typename T>
class View {
public:
void show() const {
T::showView();
}
};
// 具体视图类1:表格视图
class TableViewImpl {
public:
static void showView() {
std::cout << "Showing Table View" << std::endl;
}
};
// 具体视图类2:图形视图
class GraphicsViewImpl {
public:
static void showView() {
std::cout << "Showing Graphics View" << std::endl;
}
};
// 客户端代码
int main() {
// 创建表格视图
View<TableViewImpl> tableView;
tableView.show();
// 创建图形视图
View<GraphicsViewImpl> graphicsView;
graphicsView.show();
return 0;
}
4. 比较分析
灵活性:
- Factory Method 模式:提供了运行时的灵活性,可以通过创建不同的工厂类来创建不同的产品对象。
- C++ Template:提供了编译时的灵活性,可以通过模板参数化类型,在编译时生成不同的代码实例。
类型安全性:
- Factory Method 模式:运行时类型安全,但需要大量的类和接口定义。
- C++ Template:编译时类型安全,代码更简洁,但错误信息可能较难理解。
性能:
- Factory Method 模式:可能会有一些运行时开销,因为对象的创建是在运行时进行的。
- C++ Template:编译时生成具体代码,通常性能更高,因为没有运行时开销。
扩展性:
- Factory Method 模式:易于扩展新的产品类型,只需要添加新的工厂类和产品类。
- C++ Template:扩展性受限于模板参数类型,但可以通过模板特化或偏特化进行扩展。
总结
Factory Method 模式和 C++ Template 都是在解决对象创建和代码复用的问题,但它们的实现机制和适用场景有所不同。Factory Method 模式通过运行时多态提供了灵活的对象创建机制,适合需要根据不同条件创建不同类型对象的场景。而 C++ Template 则通过编译时参数化类型提供了类型安全和性能优化的解决方案,适合需要编写通用算法和数据结构的场景。在实际应用中,可以根据具体需求选择合适的方式来解决问题。