设计模式 ---- 工厂模式&抽象工厂模式&简单工厂
从“猫吃鱼”理解简单工厂、工厂方法与抽象工厂
这个例子只是同步哦猫吃鱼来详细理解设计模式,其他例子比如:商品打折,后需要增加春节折扣,中秋节折扣
植物大战僵尸:玩家点击卡片生成植物,生成向日葵,生成豌豆射手,后续要添加其他植物拓展
一、模式前置需求
假设现在有一个简单的需求:
有一只猫,猫可以吃鱼。
现有类:猫、鱼
存在方法:猫可以吃鱼、鱼可以被吃
class Cat
{
public:
void EatFish(Fish* fish)
{
std::cout << "猫吃鱼" << std::endl;
fish->HasBeenEat();
}
};
class Fish
{
public:
void HasBeenEat()
{
std::cout << "我是鱼,我被吃了" << std::endl;
}
}
在使用该类的时候
Cat* cat = new Cat();
Fish* fish = new Fish();
//执行猫吃鱼的动作
cat->EatFish(fish);
delete cat;
delete fish;
增加需求:猫不止要吃鱼
那么我要吃其他的食物呢,野猫会捕食野鼠
如果不使用设计模式,那么需要在原有的Cat类中修改
原类直接修改:
class Cat
{
public:
void EatFish(Fish* fish)
{
std::cout << "猫吃鱼" << std::endl;
fish->HasBeenEat();
}
void EatMouse(Mouse* mouse)
{
std::cout << "猫吃老鼠" << std::endl;
mouse->HasBeenEat();
}
};
还需新增类
class Mouse
{
public:
void HasBeenEat()
{
std::cout << "我是老鼠,我被吃了" << std::endl;
}
}
后续如果,猫需要吃兔子
class Cat
{
public:
void EatFish(Fish* fish)
{
// ...
}
void EatMouse(Mouse* mouse)
{
// ...
}
void EatRabbit(Rabbit* rabbit)
{
// ...
}
};
还需要增加兔子类
class Rabbit
{
public:
void HasBeenEat()
{
std::cout << "我是兔子,我被吃了" << std::endl;
}
};
这样如果每增加一种食物就需要修改类Cat,并且新增一个对应的食物类
业务代码同时依赖具体的 Cat 和具体的 Fish 类型。
每增加一种新的食物类型,就需要修改 Cat 类,为其增加对应的处理方法。这使得 Cat 类与具体食物类型产生了较强的耦合,也违反了开闭原则。(即:软件实体应对拓展开放,对修改关闭)
如果后继续增加需求的话,Cat类会越来越臃肿
抽象
在理想的状态下,我们增加需求,应该是增加对应的类,而不是不断的修改Cat类
Cat 应该聚焦与吃东西,而不是具体的以来某一种具体的食物
而所有的食物都有一个相同的属性:被吃掉
那么所有的食物都可以被抽象为 Food
class Food{
public:
virtual ~Food() = default;
virtual void HasBeenEat() = 0;
};
鱼继承 Food 类:
class Fish : public Food{
public:
void HasBeenEat() override
{
std::cout << "我是鱼,我被吃掉了" << endl;
}
};
老鼠集成 Food 类:
class Mouse : public Food
{
public:
void HasBeenEat() override
{
std::cout << "我是老鼠,我被吃了" << std::endl;
}
};
Cat 类依赖的是 Food 而不是具体的食物
Cat 类:
class Cat()
{
public:
void EatFood(Food* food){
std::cout << "猫吃食物" << endl;
food->HasBeenEat();
}
};
那么在使用的时候就有
Cat* cat = new Cat();
Fish* fish = new Fish();
Mouse* mouse = new Mouse();
cat->Eat(fish);
cat->Eat(mouse);
delete cat;
delete fish;
delete mouse;
这样就是 cat 依赖于 Food
老鼠、鱼、兔子 依赖于 Food
如果增加一个其他食物,只需要增加对应的一个类就行,不需要修改Cat类
但是这样还是存在一个问题,主业务代码还是依赖具体的食物,Cat需要吃对应的食物之前,还是需要一个一个的new(对应的食物)
二、简单工厂
在现阶段主业务逻辑依赖于对应的食物
如果将所有的食物的创建交给一个专门的类
enum class FoodType {
Fish,
Mouse,
Rabbit
};
class FoodFactory
{
public:
static Food* CreateFood(FoodType type)
{
switch (type)
{
case FoodType::Fish:
return new Fish();
case FoodType::Mouse:
return new Mouse();
case FoodType::Rabbit:
return new Rabbit();
default:
return nullptr;
}
}
};
这样主业务的逻辑就变成:
Cat* cat = new Cat();
Food* food = FoodFactory::CreateFood(fish);
cat->Eat(food);
delete cat;
delete food;
这样是主业务逻辑将创建对应的类的操作剥离出来,由一个专门负责对象创建的 Factory 统一封装对象的创建逻辑
三、工厂方法
简单工厂将创建逻辑剥离出来,但工厂类本身仍然依赖所有具体食物,每增加一种食物就要修改工厂类
工厂方法模式将工厂也抽象化,每个具体工厂只负责生产一种产品,增加新产品时只需新增对应的工厂子类,无需修改已有工厂。
但要注意:客户端代码中 new FishFactory() 依然依赖了具体工厂,这种依赖通常被上移到程序的最顶层(如 main 函数或配置模块),而业务逻辑层只依赖 FoodFactory 抽象基类
如果增加食物,Factory仍然会不停的修改,仍然会变得越来越臃肿
那么能不能将Factory抽象呢
就像增加食物一样,增加工厂,创建新的食物,直接增加对应的类
先提取所有共有的属性
这里是new对应的类,即:CreateFood创建食物(如果要应用到植物大战僵尸,这里也可以是,创建植物
class FoodFactory
{
public:
virtual ~FoodFactory() = default;
virtual Food* CreateFood() = 0;
};
创建一个只生成鱼的工厂
class FishFactory : public FoodFactory
{
public:
Food* CreateFood() override
{
return new Fish();
}
};
创建一个老鼠工厂
class MouseFactory : public FoodFactory
{
public:
Food* CreateFood() override
{
return new Mouse();
}
};
在使用的时候直接调用对用的工厂方法就可直接生成对应的食物
FoodFactory* factory = new FishFactory();
Food* food = factory->CreateFood();
Cat* cat = new Cat();
cat->EatFood(food);
delete cat;
delete food;
delete factory;
这样在出现需要开拓新业务(即创建新的食物、创建新的植物...)时,只需要添加新的工厂类,和新的操作实体类(food 类)
在主业务逻辑中直接调用该创建调用工厂方法即可
四、抽象工厂
增加需求
如果现在增加需求,食物获取。猫获得鱼需要垂钓,猫获取老鼠需要陷阱
class GetFood
{
virtual ~GetFood() = default;
virtual void GetFoodMethod() = 0;
}
垂钓
class Angling : public GetFood
{
void GetFoodMethod() override
{
std::cout << "进行了垂钓" << endl;
}
}
捕鼠
class Trap : public GetFood
{
public:
void GetFoodMethod() override
{
std::cout << "设置了捕鼠器" << std::endl;
}
};
现在对进行海洋食物族进行抽象
class FoodFactory
{
public:
virtual ~FoodFactory() = default;
// 创建食物
virtual Food* CreateFood() = 0;
// 创建获取食物的方法
virtual GetFood* CreateGetFoodMethod() = 0;
};
鱼产品工厂
class FishFactory : public FoodFactory
{
public:
Food* CreateFood() override
{
return new Fish();
}
GetFood* CreateGetFoodMethod() override
{
return new Angling();
}
};
class LandFoodFactory : public FoodFactory
{
public:
Food* CreateFood() override
{
return new Mouse(); // 生产老鼠
}
GetFood* CreateGetFoodMethod() override
{
return new Trap(); // 使用陷阱
}
};
主业务逻辑
FoodFactory* factory = new FishFactory();
Food* food = factory->CreateFood();
GetFood* getMethod = factory->CreateGetFoodMethod();
getMethod->GetFoodMethod();
Cat* cat = new Cat();
cat->EatFood(food);
FoodFactory* factory2 = new LandFoodFactory();
Food* food2 = factory2->CreateFood();
GetFood* method2 = factory2->CreateGetFoodMethod();
delete cat;
delete getMethod;
delete food;
delete factory;
delete method2;
delete food2;
delete factory2;
本质上,抽象工厂是对工厂方法的优化,将与对应食物的相关类也进行一次抽象
浙公网安备 33010602011771号