赞
踩
@[TOC](工厂模式(Factory Method))
通过对象超级模式绕开。动态内存分配(new),来避免对象创建过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定,它是结构抽象之后的第一步工作。
典型模式:
对象创建模式(Creational Patterns)是设计模式的一类,主要关注对象的创建过程。它们提供了一种在系统中创建对象的最佳方法,而不是通过直接实例化类的方式。
在软件系统中经常面临着创建对象的工作,由于需求的变化,需要创建的对象的具体类型经常发生变化。
但是如何应对这种变化呢?如何绕过常规的对象创建方法,提供一种封装机制来避免客户程序和这种具体对象创建工作的紧耦合?
那么工厂模式就是为了解决这类问题。
class { public: virtual void split()=0; virtual ~ISplitter(){} }; class BinarySplitter : public ISplitter{ }; class TxtSplitter: public ISplitter{ }; class PictureSplitter: public ISplitter{ }; class VideoSplitter: public ISplitter{ }; class MainForm : public Form { public: void Button1_Click(){ ISplitter * splitter= new BinarySplitter();//依赖具体类 splitter->split(); } };
这段代码展示了一个简单的面向对象设计,其中包含了一个用于演示不同分割器的类结构。具体类 MainForm
依赖于具体的分割器类,展示了如何使用这些类来进行操作。
ISplitter
class ISplitter {
public:
virtual void split() = 0;
virtual ~ISplitter() {}
};
ISplitter
是一个抽象类(接口类),定义了一个纯虚函数 split()
,表示分割器对象需要实现的行为。= 0
)使得 ISplitter
成为抽象类,不能直接实例化,只能通过继承来实现。~ISplitter()
确保派生类对象被正确销毁。class BinarySplitter : public ISplitter { public: void split() override { // 实现二进制文件的分割 } }; class TxtSplitter : public ISplitter { public: void split() override { // 实现文本文件的分割 } }; class PictureSplitter : public ISplitter { public: void split() override { // 实现图片文件的分割 } }; class VideoSplitter : public ISplitter { public: void split() override { // 实现视频文件的分割 } };
BinarySplitter
、TxtSplitter
、PictureSplitter
和 VideoSplitter
是 ISplitter
的具体实现类,每个类都实现了 split()
方法,用于处理不同类型的文件分割。MainForm
class MainForm : public Form {
public:
void Button1_Click() {
ISplitter *splitter = new BinarySplitter(); // 依赖具体类
splitter->split();
delete splitter; // 不要忘记释放内存
}
};
MainForm
继承自 Form
类(假设 Form
类定义了 GUI 窗体的基本功能)。Button1_Click()
方法模拟了一个按钮点击事件,在这个事件中创建了一个 BinarySplitter
对象并调用其 split()
方法进行分割操作。delete splitter
用于释放内存,防止内存泄漏。MainForm
类中硬编码了具体的 BinarySplitter
类,这导致代码的灵活性和可扩展性差。如果需要更换分割器类型,需要修改 MainForm
的代码。delete splitter
释放了内存,但如果 split()
方法中抛出异常,会导致内存泄漏。因此,推荐使用智能指针来自动管理内存。从上面的代码可以看出,Button1_Click函数中的ISplitter 指针需要依赖new出具体的类。来调用split函数。那么问题来了,如何绕开new? 就是我们需要一个接口创建具体的类。而且这个接口也是动态的,也就是虚函数。能实现代码中的依赖倒置原则中的具体依赖抽象。但是此时我们不可能再基类中拥有这个结构。
直接在 ISplitter
中声明 CreateSplitter
接口会引入一些设计上的问题和违反面向对象设计的原则。下面是一些关键原因:
职责单一原则(Single Responsibility Principle, SRP):
ISplitter
的职责应该是定义分割操作的接口,而不是负责创建分割器实例。将创建逻辑和分割逻辑混合在同一个接口中,会导致接口的职责过多,不符合职责单一原则。接口隔离原则(Interface Segregation Principle, ISP):
ISplitter
接口的用户可能只需要调用 split
方法,而不关心如何创建分割器实例。如果将创建方法添加到 ISplitter
中,所有实现 ISplitter
的类都必须实现这个方法,这会增加实现的复杂性,并且违反接口隔离原则。工厂模式的作用:
ISplitter
接口中,就无法利用工厂模式的优势,例如替换具体实现、延迟实例化等。可扩展性和灵活性:
ISplitter
中,添加新的分割器类型就需要修改接口及其所有实现,降低了代码的可扩展性。ISplitter
中class ISplitter { public: virtual void split() = 0; virtual ISplitter* CreateSplitter() = 0; virtual ~ISplitter() {} }; class BinarySplitter : public ISplitter { public: void split() override { // 实现二进制文件的分割 } ISplitter* CreateSplitter() override { return new BinarySplitter(); } }; // MainForm 依赖具体实现,违背单一职责原则和工厂模式的初衷 class MainForm : public Form { public: void Button1_Click() { ISplitter *splitter = new BinarySplitter(); // 或调用 splitter->CreateSplitter() splitter->split(); delete splitter; } };
此时需要新建一个接口基类,还存放CreateSplitter函数,此时就要用到工厂模式。
可以使用工厂模式或依赖注入来解决上述缺陷,使得 MainForm
不依赖具体的分割器类,从而提高代码的灵活性和可扩展性。例如:
class SplitterFactory { public: virtual ISplitter* CreateSplitter() = 0; virtual ~SplitterFactory() {} }; class BinarySplitterFactory : public SplitterFactory { public: ISplitter* CreateSplitter() override { return new BinarySplitter(); } }; class MainForm : public Form { private: SplitterFactory *factory; public: MainForm(SplitterFactory *f) : factory(f) {} void Button1_Click() { ISplitter *splitter = factory->CreateSplitter(); splitter->split(); delete splitter; } };
通过使用 SplitterFactory
,可以在运行时决定创建哪种类型的分割器,而不需要修改 MainForm
的代码,提高了系统的灵活性和可维护性。
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂模式使得一个类的实例化得到了延迟到子类中。这样使用虚函数的方式目的在于能够解耦和。
+-----------------+ | SimpleFactory | +-----------------+ | + createProduct(type: String): Product | +-----------------+ | | +-------+-------+ | | v v +----------------+ +----------------+ | ConcreteProductA | | ConcreteProductB | +----------------+ +----------------+ | + use() | | + use() | +----------------+ +----------------+ ^ ^ | | +--------+-------+ | +------+ |Product| +------+ |+use() | +------+
+-----------------+ | Factory | +-----------------+ | + createProduct() : Product | +-----------------+ | | +-------+-------+ | | v v +----------------+ +----------------+ |ConcreteFactoryA| |ConcreteFactoryB| +----------------+ +----------------+ |+createProduct(): Product|+createProduct(): Product| +----------------+ +----------------+ | | v v +----------------+ +----------------+ | ConcreteProductA | | ConcreteProductB | +----------------+ +----------------+ | + use() | | + use() | +----------------+ +----------------+ ^ ^ | | +--------+-------+ | +------+ |Product| +------+ |+use() | +------+
+--------------------+ | AbstractFactory | +--------------------+ | + createProductA(): ProductA | | + createProductB(): ProductB | +--------------------+ | +-------+-------+ | | v v +----------------+ +----------------+ | ConcreteFactory1| | ConcreteFactory2| +----------------+ +----------------+ |+createProductA(): ProductA|+createProductA(): ProductA| |+createProductB(): ProductB|+createProductB(): ProductB| +----------------+ +----------------+ | | | | v v +----------------+ +----------------+ | ConcreteProductA1 | | ConcreteProductA2 | +----------------+ +----------------+ | + use() | | + use() | +----------------+ +----------------+ ^ ^ | | +--------+-------+ | +------+ |ProductA| +------+ |+use() | +------+ | | v v +----------------+ +----------------+ | ConcreteProductB1 | | ConcreteProductB2 | +----------------+ +----------------+ | + use() | | + use() | +----------------+ +----------------+ ^ ^ | | +--------+-------+ | +------+ |ProductB| +------+ |+use() | +------+
这些图示展示了各个设计模式的主要组件及其关系,希望能帮助你更好地理解工厂模式的结构。
工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的方式,而无需在代码中显式指定要创建的具体类。工厂模式可以分为简单工厂模式、工厂方法模式和抽象工厂模式。下面分别介绍这些模式的结构。
简单工厂模式通常也被称为静态工厂方法(Static Factory Method)模式,它通过一个工厂类来创建对象。这个工厂类包含一个静态方法,根据输入的参数来决定创建哪种具体类的实例。
结构:
工厂方法模式通过定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
结构:
旨在将对象的创建过程封装起来,使得客户端代码可以依赖于接口而不是具体的实现类,从而提高代码的可维护性和可扩展性。
好
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。