本文讲解C++设计模式-工厂方法模式
目录
概述
工厂模式属于创建型模式,大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式。听上去差不多,都是工厂模式。
简单工厂模式
定义一个简单工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常具有公共的父类
简单工厂模式的核心思想是用一个工厂类来根据输入的条件产生不同的类,再调用不同类的虚函数获得不同的结果。
简单工厂模式又称为静态工厂方法模型,它属于类创建型模式。通俗的来讲就是一个工厂只做一件事,比如我要制造手机,那么这个工厂就只造手机,为什么呢,因为简单工厂返回的是一个具体的品类,并且它也能返回其他相关的品类,而这些品类都有许多共同的属性,这就需要使用基类来存放通用属性,例如手机的尺寸,屏幕的分辨率,CPU的型号。
简单工厂模式结构
在简单工厂模式中,大体分为3个角色
工厂(Factory):根据用户提供的具体产品类的参数,创建具体产品实例;
抽象产品(AbstractProduct):具体产品类的基类,包含创建产品的公共方法;
具体产品(ConcreteProduct):抽象产品的派生类,包含具体产品特有的实现方法,是简单工厂模式的创建目标。
简单工厂模式应用场景
创建某些数量不多的相关类中的具体一个类对象时,比如经典的信息管理系统,学生类,教师类等继承于基本人员信息抽象类,工厂负责创建具体的这些类。
简单工厂模式优缺点
1.简单工厂模式优点
客户端创建对象时只需要记住特定的参数,而不需要记住复杂的类名,也不用关注实现的过程。(实现了封装和部分解耦)。
创建对象不需要单独实例化,而是通过工厂类直接获取示例(实现复用)。
2.简单工厂模式缺点
实例化对象的逻辑全部封装在一个工厂类里,每次需求变化都要单独修改工厂类(违反了开闭原则),而且出了异常可能没法正常工作。
不方便扩展子类。
实例
一个手机用品生产厂(即是一个工厂 Factory),该工厂可以根据客户需求生产苹果、小米和华为手机。苹果、小米和华为手机被称为产品(Product),产品的名称可以被称为参数。客户需要时可以向工厂提供产品参数,工厂根据产品参数生产对应产品,客户并不需要关心产品生产的生产过程细节。
简单工厂基本实现流程
由上述例子,可以很容易总结出简单工厂的实现流程:
设计一个抽象产品类,它包含一些公共的实现;
从抽象产品类中派生出多个具体产品类,如苹果、小米和华为手机类等,具体产品类中实现具体产品生产的相关代码;
设计一个工厂类,工厂类中提供一个生产各种产品的工厂方法,该方法根据传入参数(产品名称)创建不同的具体产品类对象;
客户只需要调用工厂类的工厂方法,并传入具体参数,即可得到一个具体产品对象。
代码实现:
#include <iostream>
using namespace std;
//抽象产品类
class PhoneInterface
{
public:
virtual void print_brand() = 0;
};
//具体产品类
class apple : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "苹果手机" << endl;
}
};
class XiaoMi : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "小米手机" << endl;
}
};
class HuaWei : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "华为手机" << endl;
}
};
//工厂类
class Factory
{
public:
PhoneInterface* production_phone(int flag)
{
PhoneInterface* pTemp = NULL;
switch (flag) //所有的生产都集中在一个工厂中,每次修改都要在类中修改,不符合开闭原则
{
case 1:
pTemp = new apple;
break;
case 2:
pTemp = new XiaoMi;
break;
case 3:
pTemp = new HuaWei;
break;
default:
pTemp = NULL;
break;
}
return pTemp;
}
};
int main()
{
Factory* pF = NULL;
PhoneInterface* pPhone = NULL;//抽象产品
pF = new Factory;//工厂
//具体产品 1
pPhone = pF->production_phone(1);
pPhone->print_brand();
//具体产品 1
pPhone = pF->production_phone(2);
pPhone->print_brand();
//具体产品 2
pPhone = pF->production_phone(3);
pPhone->print_brand();
delete pF;
delete pPhone;
system("pause");
return 0;
}
工厂方法模式
工厂方法模式,又称工厂模式(Factory Pattern)、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
工厂方法模式角色
抽象工厂角色(Abstract Factory):描述具体工厂的公共接口,是具体工厂的父类。
具体工厂角色(Concrete Factory):描述具体工厂,创建产品的实例,供外界调用,主要实现了抽象工厂中的抽象方法,完成具体产品的创建。
抽象产品角色(Product):抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个工厂方法,因为所有创建的具体产品对象都是其子类对象。
具体产品角色(Concrete Product):具体产品角色是简单工厂模式的创建目标,所有创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的抽象方法,由具体工厂来创建,它同具体工厂之间一一对应。
优点
一个调用者想创建一个对象,只需知道其名称。
扩展性高,如果想增加一个产品,只需扩展一个工厂类。
屏蔽产品的具体实现,调用者只关心产品的接口。
缺点
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
使用场景
日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
注意事项
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
实例
#include <iostream>
using namespace std;
//抽象产品类
class PhoneInterface
{
public:
virtual void print_brand() = 0;
};
//抽象工厂类
class FactoryInterface
{
public:
virtual PhoneInterface* production_phone() = 0;
};
//苹果手机产品实现
class apple : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "苹果手机" << endl;
}
};
//小米手机产品实现
class XiaoMi : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "小米手机" << endl;
}
};
//苹果手机工厂
class AppleFactory : public FactoryInterface
{
public:
virtual PhoneInterface* production_phone()
{
return new apple;
}
};
//小米手机工厂
class XiaomiFactory : public FactoryInterface
{
public:
virtual PhoneInterface* production_phone()
{
return new XiaoMi;
}
};
int main()
{
FactoryInterface* pFactory = NULL;
PhoneInterface* pPhone = NULL;
//要生产一台苹果手机
//先创建一个苹果手机工厂
pFactory = new AppleFactory;
pPhone = pFactory->production_phone();
pPhone->print_brand();
delete pPhone;
delete pFactory;
//生产一个小米手机
pFactory = new XiaomiFactory;
pPhone = pFactory->production_phone();
pPhone->print_brand();
delete pPhone;
delete pFactory;
//工厂模式只能生产一种/一个苹果手机,我现在想生产国行、美版、港版的苹果手机
//就需要三个苹果手机工厂才行
system("pause");
return 0;
}
抽象工厂模式
抽象工厂模式是一种创建型的软件设计模式,该模式相当于升级版的工厂模式。
如果说工厂模式对应一个产品系列,那抽象工厂就对应了多个产品系列。
比如工厂模式中有手机可以生产,那抽象工厂模式就会衍生出小米工厂和苹果工厂,这两个工厂分别生产各自大陆和美版,客户只需要选择具体工厂和想要的产品即可。如果想要替换产品系列,也只需要将具体工厂切换为别的品牌就行了。
抽象工厂模式的优点:
具体类分离。具体产品类在具体工厂的实现中进行了分离和归类。
易于更换产品族。当客户想要改变整个产品族时,只需要切换具体工厂即可。
利于产品一致性。当产品族的各个产品需要在一起执行时,抽象工厂可以确保客户只操作同系列产品,而不会进行跨品牌的组合。
抽象工厂模式的缺点:
不利于添加新种类产品。每加一个新的种类,如多一个项链类型的产品,那每一个具体工厂都要进行代码的扩展,且破坏了原先规定的结构,违反了开闭原则。
实例
#include <iostream>
using namespace std;
//抽象产品
class PhoneInterface
{
public:
virtual void print_brand() = 0;
};
//抽象工厂
class FactoryInterface
{
public:
//产品线1:苹果手机
virtual PhoneInterface* production_apple() = 0;
//产品线2:小米手机
virtual PhoneInterface* production_xiaomi() = 0;
};
//大陆版苹果手机
class ChinaApple : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "大陆版本的苹果手机" << endl;
}
};
//美版的苹果手机
class UsApple : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "美版的苹果手机" << endl;
}
};
//大陆版小米手机
class ChinaXiaomi : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "大陆版本的小米手机" << endl;
}
};
//美版的小米手机
class UsXiaomi : public PhoneInterface
{
public:
virtual void print_brand()
{
cout << "美版的小米手机" << endl;
}
};
//生产大陆版本手机的工厂
class ChinaFactory : public FactoryInterface
{
public:
//产品线1:苹果手机
virtual PhoneInterface* production_apple()
{
return new ChinaApple;
}
//产品线2:小米手机
virtual PhoneInterface* production_xiaomi()
{
return new ChinaXiaomi;
}
};
//生产美版手机的工厂
class UsFactory : public FactoryInterface
{
public:
//产品线1:苹果手机
virtual PhoneInterface* production_apple()
{
return new UsApple;
}
//产品线2:小米手机
virtual PhoneInterface* production_xiaomi()
{
return new UsXiaomi;
}
};
int main()
{
FactoryInterface* pFactory = NULL;
PhoneInterface* pPhone = NULL;
//使用大陆版手机的工厂
cout << "======大陆版手机工厂======" << endl;
pFactory = new ChinaFactory;
//生产大陆版苹果手机
pPhone = pFactory->production_apple();
pPhone->print_brand();
delete pPhone;
//生产大陆版小米手机
pPhone = pFactory->production_xiaomi();
pPhone->print_brand();
delete pPhone;
delete pFactory;
//使用美版手机的工厂
cout << "======美版手机工厂======" << endl;
pFactory = new UsFactory;
pPhone = pFactory->production_apple();
pPhone->print_brand();
delete pPhone;
pPhone = pFactory->production_xiaomi();
pPhone->print_brand();
delete pPhone;
delete pFactory;
system("pause");
return 0;
}