我们假设这样一种情况,当某个工厂一直用卡车进行运输,突然增加一个需求,需要增加轮船运输,那么怎么用代码实现?
众所周知,c++是面向对象的语言,我们只要抽象出一个类,使它可以实现”轮船运输“的需求即可解决。
但是如果面对工程量巨大的业务,增加这样一种需求是极为困难的。
这个时候就需要一种能够使其过程尽可能简化的东西出来。我们把它叫做组件。
怎么正确认识组件呢?
你可以把它想象成一个螺丝钉,螺丝钉可以用于生活中的诸多方面。小到针针线线,大到航空航天,都需要用到螺丝钉。它的功能单一,但可以用于方方面面。
之后还需要知道一个概念:接口
每个组件根据接口连接起来,可以极大的简化开发过程。
所以说,组件化和接口化是未来企业代码发展的趋势。
一、工厂方法
说了这么多,我们今天讲一个最简单的设计模式——工厂方法。
工厂方法实现具体如下:
工厂方法的结构
工厂模式包含以下几个主要角色:
- 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。
- 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。
- 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
- 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象。
应用实例
- 汽车制造:你需要一辆汽车,只需从工厂提货,而不需要关心汽车的制造过程及其内部实现。
- Hibernate:更换数据库时,只需更改方言(Dialect)和数据库驱动(Driver),即可实现对不同数据库的切换。
使用场景
- 日志记录:日志可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志的位置。
- 数据库访问:当用户不知道最终系统使用哪种数据库,或者数据库可能变化时。
- 连接服务器的框架设计:需要支持 "POP3"、"IMAP"、"HTTP" 三种协议,可以将这三种协议作为产品类,共同实现一个接口。
让我们再回到最初:当某个工厂一直用卡车进行运输,突然增加一个需求,需要增加轮船运输,我们该怎么解决?
我们看下面代码的UML类图:
由UML类图看出:此处有Truck和Ship两种方式,我们用多态实现功能多样化。这样的话,如果需要再增加一种需求,我们只需要新增两个类,分别实现继承自Logistics和Transport,即可实现该需求,大大简化了流程。
具体代码如下:
#include <iostream>
//产品的接口
class Transport
{
public:
virtual ~Transport() {};
virtual void deliver() const = 0;
};
//产品A
class Truck :public Transport{
public:
void deliver()const override
{
std::cout << "卡车运输货物中" << std::endl;
}
};
//产品B
class Ship:public Transport {
public:
void deliver()const override
{
std::cout << "轮船运输货物中" << std::endl;
}
};
//创造者
class Logistics
{
public:
virtual ~Logistics() {};
//工厂方法(核心)
virtual Transport* factoryMethod() const = 0;
//
void doSomething()const
{
Transport* transport = factoryMethod();
transport->deliver();
delete transport;
}
};
//具体创造者A
class TruckLogistics :public Logistics
{
public:
virtual ~TruckLogistics() {};
virtual Transport* factoryMethod() const override
{
return new Truck();
}
};
//具体创造者B
class ShipLogistics :public Logistics
{
public:
virtual ~ShipLogistics() {};
virtual Transport* factoryMethod() const override
{
return new Ship();
}
};
int main()
{
Logistics* trucklogistics = new TruckLogistics();
trucklogistics->doSomething();
Logistics* shiplogistics = new ShipLogistics();
shiplogistics->doSomething();
shiplogistics->doSomething();
delete shiplogistics;
delete trucklogistics;
return 0;
}
二、工厂方法的优缺点
优点
- 调用者只需要知道对象的名称即可创建对象。
- 扩展性高,如果需要增加新产品,只需扩展一个工厂类即可。
- 屏蔽了产品的具体实现,调用者只关心产品的接口。
缺点
每次增加一个产品时,都需要增加一个具体类和对应的工厂,使系统中类的数量成倍增加,增加了系统的复杂度和具体类的依赖。