模式介绍:
在简单工厂模式中,可以根据参数的不同返回不同的实例。。简单工厂模式专门定义一个类来负责创建其它类的实例,被创建的实例具有共同的父类。
简单工厂模式包含三个角色:工厂角色Factory,抽象产品角色(Product)和具体产品角色(ConcreteProduct)
先做个实例来全面诠释我们的工厂模式
有一个销售管理系统支持多种支付方式,如现金支付,信用卡支付,代金券支付等,在设计过如果不使用简单工厂模式,可能会存在如下的支付方式。
void pay(string pay_type)
{
if(pay_type==现金)
{
现金支付处理手段
}
else if(pay_type==信用卡)
{
信用卡支付处理
}
else if(pay_type==代金券)
{
代金券处理
}
........
}
不同的支付方式的处理方式不同,因此代码较为冗余,并且出现新的支付方式时,我们不得不修改if else代码。代码越长王能的维护工作就月繁杂,测试难度就加大,扩展和修改就不容易。因而我们使用简单工厂对其进行重构。
一,将各种支付方式写成统一的抽象方法,为各种支付方式提供统一的接口;
class AbstractPay
{
public:
virtual void pay() = 0;
};
二,将每种支付方式封装在一个独立的类中,各个支付方式类相对独立修改其一对于其他类没有任何影响,这些独立的支付方式类充当具体的产品类角色。是抽象类的派生类
class CashPay :public AbstractPay
{
public:
CashPay()
{
}
void pay()
{
cout << "现金支付" << endl;
}
};
class CreditcardPay :public AbstractPay
{
public:
CreditcardPay()
{
}
void pay()
{
cout << "信用卡支付" << endl;
}
};
三,将针对于个种支付方式的对象的创建封装成一个统一的方法中,即:工厂化。
class PayMethodFactory
{
public:
static AbstractPay* getPayMethod(string type)
{
if (type == "cash")
{
return new CashPay;
}
else
{
return new CreditcardPay;
}
}
};
最后提供测试用
int main()
{
PayMethodFactory *pmf = new PayMethodFactory; //基类指针指向带有虚函数的派生类对象形成多态
AbstractPay* p = pmf->getPayMethod("cash");
//假定现在是现金支付
p->pay();
system("pause");
return 0;
}
由此我们总结简单抽象工厂的优点:
(1)含有必要的逻辑判断,可以决定在何时创建具体哪一个产品实例。
(2)客户无需知道所创建的具体产品类的类名,只需要知道具体产品类对应的参数即可
一句话:实现了对象的创建和使用的分离
缺点也很明显,
(1)若果现在要加入新的产品,那么就需要的工厂中加入新产品的生产代码,违背了开闭原则。
(2)由于所有的产品都在工厂中创建,一旦工厂不能正常工作,整个系统都会受到影响。
(3)使用简单工厂会增加类的个数,在一定程度上回增加系统的复杂度和理解难度
一句话:不够灵活
适用场景:
(1)创建的对象比较少:创建的对象少,不会造成工厂方法中的业务逻辑过于复杂
(2)客户只知道传入工厂类的参数,对于如何创建对象不关心。
二、抽象工厂模式
抽象工厂模式也是常见的创建型模式之一,它比工厂方法模式更加抽象。在工厂模式中具体工厂只可以生产一组具体产品,但是在抽象工厂方法中,具体工厂可以生产相关的一组具体产品,这样的产品常被称作产品族。
抽象工厂被定义为:提供一个创建一系列相关或相互依赖对象的接口。而无需指定它们具体的类。
抽象工厂包含如下角色:
(1)AbstractFactory 抽象工厂
(2)ConcreteFactory 具体工厂
(3)AbstractProduct 抽象产品
(4)ConcreteProduct 具体产品
了解这些之后,我们以一个实例来深入了解抽象工模式
模系统为改进数据库操作的性能,自定义数据库连接对象Connection和语句对象Statement,可针对于不同数据类型的数据库提供不同的连接对象和语句对象,如提供Oracle或者MySql专用连接和语句类,而且用户可以通过配置文件等方式根据实际需求动态更新系统数据库。使用抽象工厂模式
首先我们场景进行分析,画出类图
类图非常清晰的表达了各个类之间的关系,我们只要实现就好了
先写出最重要的抽象工厂类
class DBFactory
{
public:
virtual Statement* getStatement(void) = 0;
virtual Connection* getConnection(void) = 0;
};
然后定义Statement和Connection接口
class Statement
{
public:
virtual void ExeStatement() = 0;
};
class Connection
{
virtual void InConnection() = 0;
};
分别实现对于MySql和Oracle数据库操作的具体的Statement和Connetion类
class OracleConnetcion :public Connection
{
public:
void InConnection()
{
cout << "Oracle正在连接" << endl;
}
};
class MySqlConnection :public Connection
{
public:
void InConnection()
{
cout << "MySql 正在连接" << endl;
}
};
class OracleStatement :public Statement
{
public:
void ExeStatement()
{
cout << "Oracle正在执行" << endl;
}
};
class MySqlStatement :public Statement
{
public :
void ExeStatement()
{
cout << "MySql正在执行" << endl;
}
};
最后编写测试程序 main.c
int main()
{
DBFactory *dbf = new MySqlFactory;
Statement* st=dbf->getStatement();
st->ExeStatement();
system("pause");
}
抽象工厂模式的优缺点:
优点:
(1)隔离了具体类的生成过程,使得客户并不需要知道什么时候要被创建。
(2)抽象工厂模式可以实现高内聚低耦合的设计目标
(3)当一个产品的多个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终值使用同一个产品族中的对象。
(4)增加新的具体工厂和产品族很方便,无需修改已有系统,符合开闭原则。
缺点
在添加新的产品等级很复杂,需要修改抽象工厂和所有的具体工厂类,对于“开闭原则”有倾斜性。
适用场景:
(1)一个系统不应当依赖产品类实例是何时被创建,组合和表达的细节。
(2)系统中有多个产品族,而每次只使用其中某一产品族。
(3)属于同一产品族的产品族的产品将在一起使用
(4)系统提供一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于具体实现