《设计模式》学习笔记(4)——抽象工厂模式(Abstract Factory)
1、意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
2、别名
Kit
3、适用性
以下情况下可以使用此模式:
namespace My.Reading.DesignPatterns.AbstractFactory
{
public class MazeFactory
{
public MazeFactory()
{
}
public virtual Maze MakeMaze()
{
return new Maze();
}
public virtual Room MakeRoom(int roomNo)
{
return new Room(roomNo);
}
public virtual Wall MakeWall()
{
return new Wall();
}
public virtual Door MakeDoor(Room r1, Room r2)
{
return new Door(r1, r2);
}
}
}
namespace My.Reading.DesignPatterns.AbstractFactory
{
public class EnchantedMazeFactory : MazeFactory
{
public EnchantedMazeFactory()
{
}
public override Room MakeRoom(int roomNo)
{
return new EnchantedRoom(roomNo);
}
public override Door MakeDoor(Room r1, Room r2)
{
return new DoorNeedingSpell(r1, r2);
}
}
}
namespace My.Reading.DesignPatterns.AbstractFactory
{
public class DoorNeedingSpell : Door
{
public DoorNeedingSpell(Room r1, Room r2) : base(r1, r2)
{
}
public override void Enter()
{
throw new NotImplementedException();
}
public override void ShowSelfInformation()
{
Console.WriteLine("I am the door that needs spell in namespace AbstractFactory!");
}
}
public class EnchantedRoom : Room
{
public EnchantedRoom(int roomNo) : base(roomNo)
{
}
public override void Enter()
{
throw new NotImplementedException();
}
public override void ShowSelfInformation()
{
Console.WriteLine("I am the enchanted room in namespace AbstractFactory!");
}
}
}
那么,现在我们使用工厂作为参数来构建迷宫。如果我们使用普通迷宫,则传入创建普通迷宫的工厂;如果我们使用施了魔法的迷宫,则传入创建施了魔法魔法的迷宫的工厂。
namespace My.Reading.DesignPatterns.AbstractFactory
{
public class MazeGame
{
public MazeGame()
{
}
public Maze CreateMaze(MazeFactory factory)
{
Maze aMaze = factory.MakeMaze();
Room r1 = factory.MakeRoom(1);
Room r2 = factory.MakeRoom(2);
Door theDoor = factory.MakeDoor(r1, r2);
aMaze.AddRoom(r1);
aMaze.AddRoom(r2);
r1.SetSide(Direction.North, factory.MakeWall());
r1.SetSide(Direction.East, theDoor);
r1.SetSide(Direction.South, factory.MakeWall());
r1.SetSide(Direction.West, factory.MakeWall());
r2.SetSide(Direction.North, factory.MakeWall());
r2.SetSide(Direction.East, factory.MakeWall());
r2.SetSide(Direction.South, factory.MakeWall());
r2.SetSide(Direction.West, theDoor);
return aMaze;
}
}
}
这样我们便避开了使用硬编码的方法,使得程序更容易扩展。
6、实现抽象工厂的一些有用技术:
1)将工厂作为单件:一个应用中一般每个产品系列只需一个ConcreteFactory,因此工厂最好实现为一个Singleton。
2)创建产品。抽象工厂仅仅声明了创建产品的接口,真正创建是由子类实现。那么通常有可能为每个产品定义一个工厂方法。但如果是有多个可能的产品系列,具体工厂也可以使用Phototype模式来实现。其实这样的创建产品主要是为了削弱抽象工厂对产品族的约束。
PS:原文是用C++描述的,很多地方只是示意性的代码。因此有些地方可能会有错误,欢迎指正。
此文章对应的代码下载:点击此处下载
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
2、别名
Kit
3、适用性
以下情况下可以使用此模式:
• 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
• 这个系统有多于一个的产品族,而系统只消费其中某一产品族。
• 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
• 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
4、从上一篇的例子引申出来的一个问题:
上一篇我们说到了使用硬编码的方法创建一个迷宫。这次我们需要将上面的代码复用,来创建一个被施了魔法的迷宫,这个施了魔法的迷宫由施过魔法的房间,需要符咒才能通过的门以及普通的墙壁构成。那么我们来看抽象工厂是如何方便解决这个问题的。
5、例子的结构图示、代码及注释
在这里,构建迷宫的元素在MazeFactory中创建,对应的代码如下:






























注意这里并没有将MazeFactory声明为abstract,因为在这个例子中,MazeFactory既作为AbstractFactory,EnchantedMazeFactory就是继承自它;同时又作为ConcreteFactory,它仍然需要创建普通的Maze对象。那么同样它的派生类的代码如下:




















由于Wall使用的仍然是普通的Wall,因此没有必要覆盖抽象工厂的虚方法。同时为了方便,没有使用EnchantedMaze而仍然使用Maze,只是在添加Room和Door的时候添加的是EnchantedRoom和DoorNeedingSpell。
Maze由于在上一篇已经定义过了,我们不需要改变原有的代码,我们现在只需要将与原来不同的类EnchantedRoom和DoorNeedingSpell重新定义。代码如下:







































那么,现在我们使用工厂作为参数来构建迷宫。如果我们使用普通迷宫,则传入创建普通迷宫的工厂;如果我们使用施了魔法的迷宫,则传入创建施了魔法魔法的迷宫的工厂。

































这样我们便避开了使用硬编码的方法,使得程序更容易扩展。
6、实现抽象工厂的一些有用技术:
1)将工厂作为单件:一个应用中一般每个产品系列只需一个ConcreteFactory,因此工厂最好实现为一个Singleton。
2)创建产品。抽象工厂仅仅声明了创建产品的接口,真正创建是由子类实现。那么通常有可能为每个产品定义一个工厂方法。但如果是有多个可能的产品系列,具体工厂也可以使用Phototype模式来实现。其实这样的创建产品主要是为了削弱抽象工厂对产品族的约束。
PS:原文是用C++描述的,很多地方只是示意性的代码。因此有些地方可能会有错误,欢迎指正。
此文章对应的代码下载:点击此处下载
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】