工厂模式

面向对象系统的分析和设计实际上追求的就是两点:高内聚(Cohesion)、低耦合(Coupling),而为了达到这样的目的,我们会抽象出一些类的公共接口以形成抽象基类或接口,这样我们就可以通过声明一个指向基类的指针来指向实际的子类实现,达到多态的目的。

         但是这样会造成一个问题:当有许多子类继承自抽象基类,我们每一次使用子类都需要编写如:

	Figure* figure1 = new Triangle();
	Figure* figure2 = new Circle();

这样的代码(抽象基类:Figure,派生子类:Triangle、Circle)。对于客户程序员来说,就必须知道实际的子类名称(这里的Triangle、Circle),一旦子类有很多,或者命名复杂(可读性、可理解性差),就会产生问题和不便,也使得程序的扩展性和维护性变得困难。

    对于这样的问题,我们就可以使用工厂模式来解决,它的两个重要的功能:

    ①定义创建对象的接口,封装了对象的创建;

    ②使得具体化类的工作延迟到了子类中。

简单工厂模式

         简单工厂模式又称静态工厂方法模式,它用于创建对象的接口。“工厂”,顾名思义就是一个创建对象的地方,而客户程序员就是顾客,顾客要求得到什么对象,工厂就会造出什么样的对象。这样的好处,就是工厂隐藏了创建对象的细节,而且无需关心到底返回的是哪一个子类。体现在代码上,就是不用写上面那样的new语句,这样一来,我们就不用知道类名到底是什么,不管是Triangle、triangle还是TRIANGLE,还是阿猫阿狗什么的,我们只是直接调用接口。代码如下:

#include <iostream>
using namespace std;

const double PI = 3.1415926;

class Figure
{
public:
	void set_size(double x, double y = 0)
	{
		x_size = x;
		y_size = y;
	}
	virtual double get_area() = 0;
	virtual ~Figure(){}
protected:
	double x_size, y_size;
};

class Triangle: public Figure
{
public:
	virtual double get_area()
	{
		return (x_size * y_size / 2);
	}
	virtual ~Triangle(){}
};

class Circle: public Figure
{
public:
	virtual double get_area()
	{
		return (x_size * x_size * PI);
	}
	virtual ~Circle(){}
};

class SimpleFactory //工厂类
{
public:
	SimpleFactory(){}
	~SimpleFactory(){}
	Figure* createProduct( shape sh )
	{
		Figure* p = 0;
		if( sh == circle )
			p = new Circle();
		else if( sh == triangle )
			p = new Triangle();
		else
			p = NULL;
		return p;
	}
};

int main()
{
	/* 以下注释是不用工厂模式的情况
	Figure* figure1 = new Triangle;
	Figure* figure2 = new Circle;

	figure1->set_size(1.2, 1.2);
	cout << figure1->get_area() << endl;

	figure2->set_size(1.2);
	cout << figure2->get_area() << endl;

	delete figure1;
	delete figure2;
	*/
	SimpleFactory simplefactory; //调用接口来创建对象
	Figure* fig1 = simplefactory.createProduct( circle );
	Figure* fig2 = simplefactory.createProduct( triangle );

	fig1->set_size( 1.2 );
	cout << fig1->get_area() << endl;

	fig2->set_size( 1.2, 1.2 );
	cout << fig2->get_area() << endl;

	delete fig1;
	delete fig2;

	return 0;
}

这样看起来确实方便不少,但是仔细想想还是有问题:如果我们新加了一个类:Rectangle,那么我们就需要在工厂类里面添加一个接口:

else if( sh == rectangle )
    p = new Rectangle();

也就是说,每一次我们添加一个子类,就必须添加一个接口,这样就违反了大名鼎鼎的“开闭原则(OCP)”,至于“开闭原则”有什么作用、影响和实践,可参考《设计模式之禅》第6章(机械工业出版社,秦小波著)。解决方法,就是“工厂方法模式”

工厂方法模式

       我们可以想像,之前只有一个工厂,我们需要什么形状的图形就告诉工厂,然后它就会返回一个对应的对象给我们。而现在不同了,之前的工厂现在已经成为了总公司,而在总公司下面下属多个工厂。当我们需要某个对象时,直接找对应的工厂就行了,而不是告诉唯一的一个工厂要什么对象。

       体现在代码上,就是解决了简单工厂模式的一个问题:违反开闭原则。在工厂方法模式中,解决的方法就是通过工厂类的多态,将工厂的实例化过程推迟到子类中,由子类自己来实例化。这样,即使添加了子类,工厂的父类(Factory)也不需要改变,直接添加子类,推迟在客户端再来实例化。代码如下:

#include <iostream>
using namespace std;

const double PI = 3.1415926;
enum shape { triangle, circle };

class Figure
{
public:
	void set_size(double x, double y = 0)
	{
		x_size = x;
		y_size = y;
	}
	virtual double get_area() = 0;
	virtual ~Figure(){}
protected:
	double x_size, y_size;
};

class Triangle: public Figure
{
public:
	virtual double get_area()
	{
		return (x_size * y_size / 2);
	}
	virtual ~Triangle(){}
};

class Circle: public Figure
{
public:
	virtual double get_area()
	{
		return (x_size * x_size * PI);
	}
	virtual ~Circle(){}
};

class Factory //工厂父类
{
public:
	virtual Figure* createProduct() = 0;
};

class FactoryTriangle : public Factory
{
public:
	Triangle* createProduct()
	{
		return new Triangle();
	}
};

class FactoryCircle : public Factory
{
public:
	Circle* createProduct()
	{
		return new Circle();
	}
};

int main()
{
	Factory* factory1 = new FactoryTriangle();
	Figure* figure1 = factory1->createProduct();
	figure1->set_size( 1.2, 1.2 );
	cout << figure1->get_area() << endl;
	delete figure1;
	delete factory1;

	Factory* factory2 = new FactoryCircle();
	Figure* figure2 = factory2->createProduct();
	figure2->set_size( 1.2 );
	cout << figure2->get_area() << endl;
	delete figure2;
	delete factory2;

	return 0;
}


在主函数中我们可以看到,这样的设计使得工厂基类(Factory)的方法调用工厂实现类(FactoryTriangle、FactoryCircle)来创建所需的对象。

       现在又有一个问题:现在每个工厂的作用是计算面积,但是我们现在需要增加一个功能:计算周长。

       简单一想,那就是给每个类都加上一个计算周长的方法喽。于是又是给一个个类修改,费时费力。于是我们就可以用抽象工厂模式来解决。

抽象工厂模式

         抽象工厂模式将同一类的产品子类归为一类,让他们集成同一个抽象子类。在我们的例子中,就是把计算面积和计算周长分别在不同的类中实现。同时,我们设计工厂子类,每个工厂子类只负责自己的图形(三角形、圆形),而用不同的方法来负责对应的产品(面积、周长)。具体代码实现如下:

#include <iostream>
using namespace std;

const double PI = 3.1415926;
//求面积
class FigureArea
{
public:
	void set_size(double x, double y = 0)
	{
		x_size = x;
		y_size = y;
	}
	virtual double get_area() = 0;
	virtual ~FigureArea(){}
protected:
	double x_size, y_size;
};

class TriangleArea: public FigureArea
{
public:
	virtual double get_area()
	{
		return (x_size * y_size / 2);
	}
	virtual ~TriangleArea(){}
};

class CircleArea: public FigureArea
{
public:
	virtual double get_area()
	{
		return (x_size * x_size * PI);
	}
	virtual ~CircleArea(){}
};

//求周长
class FigureCircumference
{
public:
	void set_size(double x, double y = 0, double z = 0)
	{
		x_size = x;
		y_size = y;
		z_size = z;
	}
	virtual double get_Circumference() = 0;
	virtual ~FigureCircumference(){}
protected:
	double x_size, y_size, z_size;
};

class TriangleCircumference: public FigureCircumference
{
public:
	virtual double get_Circumference()
	{
		return (x_size + y_size + z_size);
	}
	virtual ~TriangleCircumference(){}
};

class CircleCircumference: public FigureCircumference
{
public:
	virtual double get_Circumference()
	{
		return (2* x_size * PI);
	}
	virtual ~CircleCircumference(){}
};


//抽象工厂类
class AbstractFactory
{
public:
	AbstractFactory(){}
	virtual ~AbstractFactory(){}

	virtual FigureArea* calculateArea() = 0;
	virtual FigureCircumference* calculateCircumference() = 0;
};

class TriangleFactory : public AbstractFactory
{
	FigureArea* calculateArea()
	{
		return new TriangleArea();
	}
	FigureCircumference* calculateCircumference()
	{
		return new TriangleCircumference();
	}

};

class CircleFactory : public AbstractFactory
{
	FigureArea* calculateArea()
	{
		return new CircleArea();
	}
	FigureCircumference* calculateCircumference()
	{
		return new CircleCircumference();
	}
};

int main()
{
	//三角形的面积与周长
	AbstractFactory* triangle_factory = new TriangleFactory();
	FigureArea* triangle_area = triangle_factory->calculateArea();
	triangle_area->set_size( 1.2, 1.2 );
	cout << triangle_area->get_area() << endl;

	FigureCircumference* triangle_circumference = triangle_factory->calculateCircumference();
	triangle_circumference->set_size( 1.2, 1.2, 1.2 );
	cout << triangle_circumference->get_Circumference() << endl;

	delete triangle_factory;
	delete triangle_area;
	delete triangle_circumference;

	//圆形的面积与周长
	AbstractFactory* circle_factory = new CircleFactory();
	FigureArea* circle_area = circle_factory->calculateArea();
	circle_area->set_size( 1.2 );
	cout << circle_area->get_area() << endl;

	FigureCircumference* circle_circumference = circle_factory->calculateCircumference();
	circle_circumference->set_size( 1.2 );
	cout << circle_circumference->get_Circumference() << endl;

	delete circle_factory;
	delete circle_area;
	delete circle_circumference;

	return 0;
}

 

从代码的实现中我们可以看到,在这种模式下,对于客户端来说只有TriangleFactory和CircleFactory两种产品,使用的时候直接使用,而通过工厂本身的方法来得到面积或周长。

         显然,这种模式封装了产品的创建,我们从之前的只能计算面积,进一步添加了方法:计算周长。但是客户端又可以不需要知道具体是哪种方法,只需要知道那个工厂就可以。这样无疑会使得模式灵活性更强。

        


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值