设计模式之工厂模式

简单工厂模式

定义

 简单工厂模式(Simple Factroy Pattern):定义一个工厂类,它可*根据参数的不同返回不同的实例被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。

Q 为什么工厂中的创建实例方法是静态方法

A 因为不需要使用创建对象的方法来实例化对象,因此可以使用静态方法来创建一个简单的工厂

要点

 需要什么,就像工厂传入一个正确的参数,就可以获得所需要的对象,而无需知道创建细节。UML图如下

设计模式之工厂模式_第1张图片

图中要三个不同的角色:

  1. Factory(工厂角色):也就是图中的简单工厂类,是简单工厂模式的核心,负责实现所有产品实例花的内部逻辑。
  2. Product(抽象产品角色):也就是图中的运算类,封装了各种产品对象的公有方法,提高系统的灵活性以及拓展性,所有创建的具体产品对象都是其子类对象。
  3. ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。

代码实现

Product(抽象产品角色)

class Operation {
	public:
		virtual double getResult(double A,double B) = 0;
};

ConcreteProduct(具体产品角色)

class Add : public Operation {
	public:
		virtual double getResult(double A, double B) {
			return A + B;
		}
};

class Sub : public Operation {
	public:
		virtual double getResult(double A, double B) {
			return A - B;
		}
};

class Mul : public Operation {
	public:
		virtual double getResult(double A, double B) {
			return A * B;
		}
};

class Div : public Operation {
	public:
		virtual double getResult(double A, double B) {
			if(B == 0) cout << "除数不能为0" << endl;
			else
				return A / B;
		}
};

Factory(工厂角色)

class EasyFactory {
	public:
		static Operation* createOperation(char src) {
			Operation* op = nullptr;
			switch(src) {
				case '+':
					op =  new Add();
					break;
				case '-':
					op = new Sub();
					break;
				case '*':
					op =  new Mul();
					break;
				case '/':
					op = new Div();
					break;
				default:
					cout << "输入错误" << endl;
			}
			return op;
		}
};

客户端:

int main() {
	Operation* add = EasyFactory::createOperation('+');
	Operation* sub = EasyFactory::createOperation('-');
	Operation* mul = EasyFactory::createOperation('*');
	Operation* div = EasyFactory::createOperation('/');
	
	cout << "2 + 2 = " << add->getResult(2,2) << endl;
	cout << "2 - 2 = " <<  sub->getResult(2,2) << endl;
	cout << "2 * 2 = " <<  mul->getResult(2,2) << endl;
	cout << "2 / 2 = " <<  div->getResult(2,2) << endl;
	return 0;
}

输出结果:

设计模式之工厂模式_第2张图片

优点和缺点

优点
  1. 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
  2. 客户端无需知道所创建具体产品的类名,只需知道参数即可。
  3. 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类
缺点
  1. 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且==工厂类代码会非常臃肿,违背高聚合原则。==使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
  2. 系统扩展困难,每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,违背了“开闭原则”。一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
  3. 简单工厂模式使用了 static 工厂方法造成工厂角色无法形成基于继承的等级结构
应用场景

 对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。

工厂模式

定义

 在工厂模式中,工厂父类负责定义创建产品对象的公告接口,而工厂子类负责生成具体的产品对象目的是将产品的实例化操作延迟到工厂子类中完成,通过工厂子类来确定究竟应该实例化哪一个具体产品类。这相当于是把原本会因为业务代码而庞大的简单工厂类,拆分成了一个个的工厂类,这样代码就不会都耦合在同一个类里了(解耦)。

要点

设计模式之工厂模式_第3张图片

设计模式之工厂模式_第4张图片

图中四个重要的角色:

  1. Product (抽象产品):即运算类接口。抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,也是产品对象的共同父类或接口。
  2. ConcreteProduct(具体产品):即加法类等。具体产品实现了抽象产品的接口,某种类型的具体产品由专门的具体工厂创建。
  3. Factory(抽象工厂)
  4. ConcreteFactory(具体工厂)

 具体工厂是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。

代码实现

Product抽象产品

class Operation {
	public:
		virtual double getResult(double A,double B) = 0;
};

ConcreteProduct具体产品

class Add : public Operation {
	public:
		virtual double getResult(double A, double B) {
			return A + B;
		}
};

class Sub : public Operation {
	public:
		virtual double getResult(double A, double B) {
			return A - B;
		}
};

class Mul : public Operation {
	public:
		virtual double getResult(double A, double B) {
			return A * B;
		}
};

class Div : public Operation {
	public:
		virtual double getResult(double A, double B) {
			if(B == 0) cout << "除数不能为0" << endl;
			else
				return A / B;
		}
};

Factory抽象工厂

class Factory {
	public:
		virtual Operation* createOperation() = 0;
};

ConcreteFactory具体工厂

class AddFactory : public Factory {
	public:
		virtual Operation* createOperation() {
			cout << "加法运算" ;
			return new Add();
		}
};

class SubFactory : public Factory {
	public:
		virtual Operation* createOperation() {
			cout << "减法运算" ;
			return new Sub();
		}
};

class MulFactory : public Factory {
	public:
		virtual Operation* createOperation() {
			cout << "乘法运算" ;
			return new Mul();
		}
};

class DivFactory : public Factory {
	public:
		virtual Operation* createOperation() {
			cout << "除法运算" ;
			return new Div();
		}
};

客户端:

int main() {
	Factory * af = new AddFactory();
	Operation* add = af->createOperation();
	cout << "2 + 2 = " << add->getResult(2,2) << endl;
	
	Factory * sf = new SubFactory();
	Operation* sub = sf->createOperation();
	cout << "2 - 2 = " <<  sub->getResult(2,2) << endl;
	
	Factory * mf = new MulFactory();
	Operation* mul = mf->createOperation();
	cout << "2 * 2 = " <<  mul->getResult(2,2) << endl;
	
	Factory * df = new DivFactory();
	Operation* div = df->createOperation();
	cout << "2 / 2 = " <<  div->getResult(2,2) << endl;
	return 0;
}

优点和缺点

优点

 系统的扩展性好,符合“开闭原则” 。系统加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品即可

缺点

 在添加新产品时,需要编写新的具体产品类,而且要提供与之对应的具体工厂类,系统中类的个数将成对增加,一定程度上增加了系统的复杂度

应用场景

 工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品

  1. 在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式;
  2. 产品结构较复杂的情况下,可以使用工厂方法模式;

抽象工厂

定义

 抽象工厂模式是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型,它提供了一种创建对象的最佳方式。

要点

设计模式之工厂模式_第5张图片

角色:

  1. 抽象工厂(Abstract Factory):用于声明创建抽象产品的方法
  2. 具体工厂(Concrete Factory):实现抽象工厂声明的抽象工厂方法用于创建具体产品
  3. 抽象产品(Abstract Product)为每一种产品构成声明接口
  4. 具体产品(Concrete Product):定义具体的工厂所创建的具体产品对象类型

抽象工厂(Abstract Factory):

class IDBFactory{
public:
    virtual IDBConnection* CreateDBConnection()=0;
    virtual IDBCommand* CreateDBCommand()=0;
    virtual IDataReader* CreateDataReader()=0;
    
};

具体工厂(ConcreteFactory):

class SqlDBFactory:public IDBFactory{
public:
    virtual IDBConnection* CreateDBConnection()=0;
    virtual IDBCommand* CreateDBCommand()=0;
    virtual IDataReader* CreateDataReader()=0;
 
};

class OracleDBFactory:public IDBFactory{
public:
    virtual IDBConnection* CreateDBConnection()=0;
    virtual IDBCommand* CreateDBCommand()=0;
    virtual IDataReader* CreateDataReader()=0;
 
};

抽象产品(AbstractProduct):

//数据库访问有关的基类
class IDBConnection{
    
};

class IDBCommand{
    
};

class IDataReader{
    
};

具体产品(ConcreteProduct):

//支持SQL Server
class SqlConnection: public IDBConnection{
    
};
class SqlCommand: public IDBCommand{
    
};
class SqlDataReader: public IDataReader{
    
};

//支持Oracle
class OracleConnection: public IDBConnection{
    
};

class OracleCommand: public IDBCommand{
    
};

class OracleDataReader: public IDataReader{
    
};

客户端:

int main(){
	IDBFactory *sqlFactory = new SqlDBFactory();
	IDBFactory *oracleFactory = new OracleDBFactory();
	// 创建实例
    IDBComman* sqlCommand = SqlDBFactory->CreateDBCommand();
    IDBConnect* sqlConnect = SqlDBFactory->CreateDBConnection();
    IDataReader* sqlReader = SqlDBFactory->CreateDataReader();
    
    IDBComman* oracleCommand = oracleFactory->CreateDBCommand();
    IDBConnect* oracleConnect = oracleFactory->CreateDBConnection();
    IDataReader* oracleReader = oracleFactory->CreateDataReader();
}

具体例子

 如上代码所示数据库相关内容,数据库操作有连接、指令、读取数据等。同时数据库有多种类型,比如说sqlServer、Oracle等,不同的数据库对应的指令操作、连接操作等大有不同。如果指令操作不能对应上数据库,那么就不能正常运行。这时候比较恰当的做法是把与数据库对应的操作封装在一起,使得相关组件达到高内聚的效果。

优点和缺点

优点
  • 你可以确保同一工厂生成的产品相互匹配。
  • 你可以避免客户端和具体产品代码的耦合
  • 单一职责原则。 你可以将产品生成代码抽取到同一位置, 使得代码易于维护。
  • 开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码。
缺点

 如果工厂中产品族中要增加一个新的产品时所有的工厂类都要进行修改(具体工厂继承于抽象工厂)。增加了系统的抽象性和理解难度。

应用场景

 如果代码需要与多个不同系列的相关产品交互, 但是由于无法提前获取相关信息, 或者出于对未来扩展性的考虑,你不希望代码基于产品的具体类进行构建, 在这种情况下, 你可以使用抽象工厂。

  • 抽象工厂提供了一个接口, 用于创建每个系列产品的对象。 只要代码通过该接口创建对象,那么就会生成与应用程序已生成的产品类型一致的产品。
  • 如果有一个基于一组抽象方法的类, 且其主要功能因此变得不明确, 那么在这种情况下可以考虑使用抽象工厂模式。
  • 在设计良好的程序中, 每个类仅负责一件事。 如果一个类与多种类型产品交互,就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。

你可能感兴趣的:(设计模式,设计模式,uml)