前言
本文的知识都出自于『Head First 设计模式』这本书中,
这里只是做一个概括,等后来忘记了拿来复习。
你可以也将本文作为复习参考,
不过要学的话,建议还是去看原书吧。
看这本书不一定非要会Java,我就是用C++实现的。
简单工厂
简单工厂其实不是一种设计模式,倒像是一种编程习惯。
其实就是把创建动态对象的代码独立封装出类就是了。
这样将来要是想改动创建对象这部分的代码,
只需要改那个类就可以,不必动原来的代码。
一般我们会经常用到简单工厂。
UML与代码示例
这里构建了一个简易的军火商与简易工厂,
军火商根据类型需求生产步枪/火箭/狙击枪,并装填弹药,最后将携带弹药的武器return。
可以看到,军火商并不是自己生产武器,
而是封装出了一个简易工厂,把生产武器的操作外包给它。
将来如果我们需要生产新的武器,就修改简易工厂的代码,
而不需要改动军火商客户类。
顺便说一句,你也可以将CreateWeapon改造成静态方法,
这样调用它时,就不用实例化它的对象,
不过也就不能通过创造简易工厂的子类来改变CreateWeapon的具体行为了。
由于我自己暂时没什么体会,从网上找了简单工厂的优缺点:
优点
工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点
由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
工厂方法模式
定义
工厂方法模式(Factory Method Pattern)定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
让我们回忆简单工厂,它的做法是将创建对象的代码独立封装出一个简单工厂类。
那么在工厂方法模式,创建对象的代码则并没有外包,而是留在了客户类,
那么客户类就拥有生产的一系列流程,它称为创建者类(Creator)。
而工厂方法模式的关键就在于:创建者类关于创建对象的函数被设定为了纯虚函数(或者说抽象函数),留给子类去实现。
UML示例
社会主义军工部门和军火商不一样,
它同样负责武器制造而不会拿去外包,
WeaponCreator的两个子类都继承了CreateWeapon方法并实现,
由于国情不同,这两个子类能生产的武器并不一样。
同为军工部门,
SovietCreator可以生产冲锋枪、反坦克步枪、机枪、半自动步枪,
可是有些人却只能生产一些破烂玩意儿,
比如仿造十九世纪的汉阳造、搞点土枪塞给民兵、修一修破烂三八式什么的,可见当年条件之艰苦。
工厂方法模式就是让子类去具体实现创建对象的方法,
这样就可以让子类决定该创建什么对象,同时这种操作也达到了封装创建对象的代码的目的。
它的思想是使创建者类本身与创建对象的代码解耦,
所以,就算工厂只有一个,工厂方法模式也是有用的。
对了,工厂方法模式是不是违背了“多用组合少用继承”的OO原则?
抽象工厂模式
定义
抽象工厂模式(Abstract Factory Pattern)提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
理解
抽象工厂模式就像是简单工厂和工厂方法模式的结合体。
简单工厂是把创建对象的代码封装出去成为一个类,
工厂方法模式是把创建对象的代码推迟到子类去实现。
那么抽象工厂模式……
抽象工厂模式就是又把创建对象的代码封装出去,又套了一层抽象类,把创建对象的代码推迟到子类去实现。
这样一来,客户类不再具体实现产品对象的生成,甚至是工厂对象的生成,
这就使得我们扩展或者修改工厂或者产品类的代码,
都不会影响到客户类。
这种高内聚低耦合的设计很符合开闭原则,
它用组合而不是继承来实现创建产品对象,
这是与工厂方法模式最本质的区别。
所以,当我们需要使工厂创建一系列不同种类的产品对象时,则应使用抽象工厂模式,
若是只需要创建不同形式的同种产品,比如生产各种步枪,或者是生产各种披萨,则应使用简单工厂或者工厂方法模式。
抽象工厂模式也体现了依赖倒置原则:要依赖抽象,不要依赖具体类。
无论是客户端对于工厂,还是工厂对于产品,
它们依赖的都是抽象类而不是具体类。
这种设计使得扩展新工厂或者扩展现有产品的新形式很方便,
可是它也有缺点,
那就是扩展新的种类的产品就比较麻烦,
因为需要修改工厂接口的代码,从而还需要修改它的所有子类的代码。
比如一个服装厂,安排生产一套新式服装相对容易,可是安排生产口罩那就比较难了。
UML示例
这里为了方便,我没有写客户类,直接就在Main方法里构建工厂实例了。
军队只有枪,没有吃的和穿的,那是打不赢仗的。
所以军工部门不仅需要步枪,还需要口粮和衣服。
既然要生产一系列产品而不仅仅是步枪,那么工厂方法模式就不合适了,我们需要采用抽象工厂模式。
将来也许要添加新的产品,
比如LeningradFactory会生产Macaroni and Meat以代替Black Bread,
YananFactory会生产PLA Uniform以代替Grey National Revolutionary Uniform,
那么只要分别新建Meal与Clothes的子类用于代替就好了。
添加新的工厂也很方便,
比如将来需要新建两个军工厂BerlinerFabrik与TokyoKojo来扩大产能,
那么只需要新建两个CommunistFactory的子类并设定好它们将要生产什么就好了。
但是有一天,YananFactory不生产Rifle,转而生产LaserCannon给同志们人手一个,
那么就很麻烦了,就需要修改CommunistFactory这个接口。
还需要修改YananFactory这个子类。
可是这就完了吗?
当然没有,LeningradFactory可不会生产LaserCannon,
如果程序哪天调用LeningradFactory.CreateLaserCannon,
那就要出错了。
所以其他子类也都需要修改。
代码示例
Rifle.hpp:
#pragma once
#include <string>
class Rifle
{
public:
std::string Name;
};
class Bianquzao :
public Rifle
{
public:
Bianquzao()
{
Name = "Bianquzao";
}
};
class MosinNagant :
public Rifle
{
public:
MosinNagant()
{
Name = "Mosin-Nagant";
}
};
Meal.hpp:
#pragma once
#include <string>
class Meal
{
public:
std::string Name;
};
class MilletandBlackBeans :
public Meal
{
public:
MilletandBlackBeans()
{
Name = "Millet and Black Beans";
}
};
class BlackBread :
public Meal
{
public:
BlackBread()
{
Name = "Black Bread";
}
};
Clothes.hpp:
#pragma once
#include <string>
class Clothes
{
public:
std::string Name;
};
class GreyNationalRevolutionaryUniform :
public Clothes
{
public:
GreyNationalRevolutionaryUniform()
{
Name = "Grey National Revolutionary Uniform";
}
};
class SovietMilitaryUniform :
public Clothes
{
public:
SovietMilitaryUniform()
{
Name = "Soviet Military Uniform";
}
};
CommunistFactory.hpp:
#pragma once
#include <vector>
#include <iostream>
#include "Clothes.hpp"
#include "Meal.hpp"
#include "Rifle.hpp"
class CommunistFactory
{
protected:
std::vector<Rifle> Rifles;
std::vector<Meal> Meals;
std::vector<Clothes> Clothes;
public:
virtual void CreateRifle() = 0;
virtual void CreateMeal() = 0;
virtual void CreateClothes() = 0;
void Show()
{
if (Rifles.empty())
std::cout << "We have produced no rifles." << std::endl;
else
std::cout << "We have produced" << ' ' << Rifles.size() << ' ' << Rifles[0].Name << std::endl;
if (Meals.empty())
std::cout << "We have produced no meals." << std::endl;
else
std::cout << "We have produced" << ' ' << Meals.size() << ' ' << Meals[0].Name << std::endl;
if (Clothes.empty())
std::cout << "We have produced no clothes." << std::endl;
else
std::cout << "We have produced" << ' ' << Clothes.size() << ' ' << Clothes[0].Name << std::endl;
}
};
class LeningradFactory :
public CommunistFactory
{
virtual void CreateRifle() override
{
Rifles.push_back(MosinNagant());
}
virtual void CreateMeal() override
{
Meals.push_back(BlackBread());
}
virtual void CreateClothes() override
{
Clothes.push_back(SovietMilitaryUniform());
}
};
class YananFactory :
public CommunistFactory
{
virtual void CreateRifle() override
{
Rifles.push_back(Bianquzao());
}
virtual void CreateMeal() override
{
Meals.push_back(MilletandBlackBeans());
}
virtual void CreateClothes() override
{
Clothes.push_back(GreyNationalRevolutionaryUniform());
}
};
Main.cpp:
#include <iostream>
#include "CommunistFactory.hpp"
int main()
{
CommunistFactory* cf = new LeningradFactory();
cf->CreateClothes();
cf->CreateClothes();
cf->CreateClothes();
cf->CreateRifle();
cf->CreateRifle();
cf->CreateRifle();
cf->CreateRifle();
cf->CreateRifle();
cf->CreateMeal();
cf->CreateMeal();
cf->CreateMeal();
cf->Show();
delete cf;
cf = new YananFactory();
cf->CreateRifle();
cf->CreateRifle();
cf->CreateRifle();
cf->CreateMeal();
cf->CreateClothes();
cf->Show();
delete cf;
cf = new YananFactory();
cf->Show();
delete cf;
}
转载:https://blog.csdn.net/RabbitLime/article/details/106563812