工厂模式又称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 协议 ,转载请注明出处!

策略模式 上一篇
桥接模式 下一篇