工厂模式又称Factory Method,属于对象创建模式中的一种,用来支持对象稳定的创建。
定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。 — 《设计模式》 GoF
动机
根据设计模式的依赖倒置原则,1 高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口,2抽象接口不应该依赖于具体实现,而具体实现则应该依赖于抽象接口,因此如果代码像下面这么写:
mybook *book = new Mathbook;
这种写法虽然定义虽然是面向接口编程,但是new的却是一个具体的类,因此不符合依赖倒置原则,那么如何创建对象才符合DIP原则呢?
这就是工厂模式需要解决的问题,创建一个工厂类,通过内部的方法返回一个具体的对象。
具体实施方法:
- 创建一个工厂接口,提供返回对象的纯虚方法
- 对于每一个具体的子类,创建一个具体的工厂类继承工厂接口
缺点:
- 要求每一个子类的构造方法的参数相同
模式分析
- Creator : 需要产生对象的接口
- Concretecreator : 需要产生对象的具体类
- Product : 工厂类,负责产生具体的Concretecreator对象
代码分析
书本抽象类
书本抽象类是所有书类的接口
class Book
{
public:
Book();
virtual ~Book();
virtual void getbookname() = 0;
};
两个书本类
两个书本类是书本抽象类的实例化
class EnglishBook : public Book
{
public:
EnglishBook();
virtual ~EnglishBook();
virtual void getbookname();
};
void EnglishBook::getbookname()
{
std::cout << "this is English book\n";
}
class MathBook : public Book
{
public:
MathBook();
virtual ~MathBook();
virtual void getbookname();
};
void MathBook::getbookname()
{
std::cout << "this is math book \n";
}
工厂类的接口
工厂类的接口是所有工厂子类的父类,每一个书本类都有对应的一个工厂类,在运行时决定采用哪个工厂类返回哪种类型的书本
class BookFactory
{
public:
BookFactory();
virtual ~BookFactory();
virtual Book *Createbook() = 0;
};
具体的工厂类
每一个需要创建的子类都对应一个具体的工厂类,这个类负责返回这个子类的对象
class EnglishBookFactory : public BookFactory
{
public:
EnglishBookFactory();
~EnglishBookFactory();
virtual Book *Createbook();
};
Book * EnglishBookFactory::Createbook()
{
return new EnglishBook;
}
class MathBookFactory
{
public:
MathBookFactory();
~MathBookFactory();
virtual Book *Createbook();
};
Book * MathBookFactory::Createbook()
{
return new MathBook;
}
界面显示类
这个类用来调用book类里面的函数,显示book的名字,这里采用工厂模式的目的就是为了使这个类是稳定的,即不管书的类型怎么变化,无需修改这个类的代码,这也是设计模式的一个核心思想,需求变化通过添加代码实现,而不是修改代码。
可以看到这里面所有的类型都是接口,符合DIP原则。
设计模式不可能完全把不稳定的东西去除,这是不符合实际场景的,但是可以将不稳定的部分放在一个范围内而不是整个代码中,MainForm通过其构造函数传入一个具体的工厂,然后创建具体的Book对象。
class MainForm
{
BookFactory *book_fac;
public:
MainForm(BookFactory *fac);
~MainForm();
void showbook();
};
MainForm::MainForm(BookFactory *fac)
{
this->book_fac = fac;
}
MainForm::~MainForm()
{
}
void MainForm::showbook()
{
Book *book = this->book_fac->Createbook(); // 多态new
book->getbookname();
}
main函数测试
int main()
{
BookFactory *fac = new EnglishBookFactory;
MainForm *mainform = new MainForm(fac);
mainform->showbook();
}
测试结果
类图
应用场景
思考一个问题:上面的例子的MainForm中直接传入Book的对象指针不就行了吗?Book也是接口,因此MainForm也是稳定的
由此引出Factory模式的应用场景和局限性:
工厂模式所实例化的对象常常具有私有的构造方法,因此这些类就不能扩展了
如果将所有的构造方法都用工厂实现,则常常会把构造函数设置为私有的,那么所有的new这个对象的代码都会失效
如果确实扩展了工厂方法所实例化的类,那么其子类必须具有自己的工厂类,否则调用工厂方法返回的是父类的实例而不是子类的实例
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!