对设计模式的总结之工厂方法模式和抽象工厂模式
前言
面向对象编程追求的本质-提高扩展性、可维护性、灵活性和复用性。合理利用面向对象6个原则,能够很好的达到要求。如何利用好就是至关重要的了,前人总结了23+个设计模式能够让初学者更容易学到其中的精髓,本文就说说我对本人对工厂方法模式和抽象工厂模式的见解。
设计模式链接
工厂方法模式与抽象工厂模式
工厂方法模式
在过去,许多大型项目都是一个整体,各个模块都用一套技术完成,部署的时候也是每台服务器上都是整套部署。每次版本升级都需要将整个项目全部升级完毕才能够重新部署。如果是迭代N年,非常庞大的项目,可能一次版本升级就会弄残一堆研发。为了使版本升级更灵活,开发技术不局限一套,微服务就诞生了--将一个大系统拆分成N个单独功能的子系统,分开部署在不同服务器,版本升级也不需要整套系统一起升级。
现在某个子系统需要增加一个与N个游戏子系统交互的功能,而且后期还会不断增加新的游戏子系统。考虑到后期会增加游戏子系统,用简单工厂除了增加新的交互类,还需要更改工厂方法,破坏了开放封闭原则。那还有什么更好一些的办法吗?可以考虑工厂方法模式:定义一个创建产品对象的工厂抽象类(抽象类或接口),利用继承的好处,将具体的创建工作"延时"到子类进行。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的基类,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
基本用法
-
/// <summary> /// 抽象工厂角色 /// </summary> public abstract class FuncFactory { /// <summary> /// 生成产品的对象抽象 /// </summary> /// <returns></returns> public abstract GameInteraction Create(); } public class AGameInteractionFactory : FuncFactory { /// <summary> /// 实现具体产品生产(生成具体交互类实例) /// </summary> /// <returns></returns> public override GameInteraction Create() { return new AGameInteraction(); } } public class BGameInteractionFactory : FuncFactory { /// <summary> /// 实现具体产品生产(生成具体交互类实例) /// </summary> /// <returns></returns> public override GameInteraction Create() { return new BGameInteraction(); } } /// <summary> /// 与游戏服务端交互抽象 /// </summary> public abstract class GameInteraction { /// <summary> /// 与游戏交互方法(都需要和游戏端交互) /// </summary> /// <param name="sloginName">账号</param> /// <returns></returns> public abstract string InfoInteaction(string sloginName); } public class AGameInteraction: GameInteraction { /// <summary> /// 与游戏A交互方法 /// </summary> /// <param name="sloginName">账号</param> /// <returns></returns> public override string InfoInteaction(string sloginName) { return sloginName+"通过TCP/IP方式与GameA具体交互逻辑..."; } } public class BGameInteraction : GameInteraction { /// <summary> /// 与游戏B交互方法 /// </summary> /// <param name="sloginName">账号</param> /// <returns></returns> public override string InfoInteaction(string sloginName) { return sloginName+"通过HTTP方式与GameB具体交互逻辑..."; } } 客户端使用: //获取程序集路径 string assemblyName = AppDomain.CurrentDomain.BaseDirectory+ "ObjectOriented_Tools.dll"; //反射AGameInteractionFactory生成实例,赋值给FuncFactory //FuncFactory reflect = (FuncFactory)Assembly.LoadFile(assemblyName).CreateInstance("ObjectOriented_Tools.FuncFactory.AGameInteractionFactory"); FuncFactory reflect = (FuncFactory)Assembly.Load("ObjectOriented_Tools").CreateInstance("ObjectOriented_Tools.FuncFactory.AGameInteractionFactory"); GameInteraction gameInteraction = reflect.Create();//创建具体交互实例 txt_description.Text ="反射操作:\r\n"+ gameInteraction.InfoInteaction("铁锅盖")+ "\r\n"; //交互 //选择具体工厂实例化后,赋值给工厂基类 FuncFactory rct = new BGameInteractionFactory(); GameInteraction interaction = rct.Create();//创建具体交互实例 txt_description.Text += "一般操作:\r\n" + interaction.InfoInteaction("铁锅盖"); //交互
总结
优缺点:
1、符合面向对象编程的开放封闭原则,增加新的产品,只需要增加新的工厂类即可(对扩展开放),对任何产品的增加或修改,不会影响其它工厂类和产品类(对修改封闭);
2、相对简单工厂模式,产品多的时候,系统中的类会成倍增加,造成系统不简洁,增加了工厂类的创建。
3、用户的选择产品逻辑变成了对工厂类的选择,降低了选择的直观性。
使用场景:
适用于某个功能多种实现,且返回统一。
抽象工厂模式
需要为一个制衣公司做一个制衣管理系统。制衣公司的产品对象是面向世界,生产全世界所有人种的衣服。制衣公司需要实现对应不同人种(eg:USA,JP,CN),生产出对应尺寸的服装。考虑到服装种类繁多,单用上面介绍的工厂方法,显然不行。那么,能否有适合的设计模式吗?有的,就是工厂方法的更一般的表达-抽象工程:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
基本用法
-
/// <summary> /// 抽象工厂(Abstract Factory)角色:工厂方法模式的核心,它是与应用系统商业逻辑无关的。 /// </summary> public abstract class ClothingProductFactory { /// <summary> /// 实例化生产衣服工厂抽象 /// </summary> /// <returns></returns> public abstract AbstractClothes CreateClothes(); /// <summary> /// 实例化生产裤子工厂抽象 /// </summary> /// <returns></returns> public abstract AbstractTrousers CreateTrousers(); } /// <summary> /// 具体工厂(Concrete Factory)角色:直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。 /// 生产中国服装工厂 /// </summary> public class ClothingOfCNFactory:ClothingProductFactory { /// <summary> /// 实例化生产衣服工厂 /// </summary> /// <returns></returns> public override AbstractClothes CreateClothes() { return new ClothesOfCN(); } /// <summary> /// 实例化生产裤子工厂 /// </summary> /// <returns></returns> public override AbstractTrousers CreateTrousers() { return new TrousersOfCN(); } } /// <summary> /// 具体工厂(Concrete Factory)角色:直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。 /// 生产日本人服装工厂 /// </summary> public abstract class ClothingOfJPFactory: ClothingProductFactory { /// <summary> /// 实例化生产衣服工厂 /// </summary> /// <returns></returns> public override AbstractClothes CreateClothes() { return new ClothesOfJP(); } /// <summary> /// 实例化生产裤子工厂 /// </summary> /// <returns></returns> public override AbstractTrousers CreateTrousers() { return new TrousersOfJP(); } } /// <summary> /// 抽象产品(Abstract Product)角色:是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。 /// </summary> public abstract class AbstractClothes { /// <summary> /// 生产合适人尺寸的衣服 /// </summary> /// <returns></returns> public abstract string ProductClothes(); } public class ClothesOfCN : AbstractClothes { /// <summary> /// 生产合适中国人中等体型的衣服 /// </summary> /// <returns></returns> public override string ProductClothes() { return "生产合适中国人中等体型的衣服..."; } } public class ClothesOfJP: AbstractClothes { /// <summary> /// 生产合适日本人小体型的衣服 /// </summary> /// <returns></returns> public override string ProductClothes() { return "生产合适日本人小体型的衣服..."; } } /// <summary> /// 抽象产品(Abstract Product)角色:是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。 /// </summary> public abstract class AbstractTrousers { /// <summary> /// 生产合适尺寸的裤子 /// </summary> /// <returns></returns> public abstract string ProductTrousers(); } public class TrousersOfCN : AbstractTrousers { /// <summary> /// 生产中国人尺寸裤子 /// </summary> /// <returns></returns> public override string ProductTrousers() { return "中国人体格中等,生产标准尺寸的裤子..."; } } public class TrousersOfJP : AbstractTrousers { /// <summary> /// 生产中国人尺寸裤子 /// </summary> /// <returns></returns> public override string ProductTrousers() { return "中国人体格大,生产宽松尺寸的裤子..."; } } //客户端生产中国人服装 ClothingProductFactory cnFunctory = new ClothingOfCNFactory(); AbstractClothes clothes=cnFunctory.CreateClothes(); AbstractTrousers trousers = cnFunctory.CreateTrousers(); txt_description.Text = clothes.ProductClothes()+ "\r\n"; txt_description.Text += trousers.ProductTrousers();
总结
优缺点:
1、有工厂方法模式的优点。
2、可以在类的内部对产品族进行约束。可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。
3、扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。
使用场景:
一般可以表达为矩阵模型,同一行的是不同环境中的同一个产品的实现,同一列的产品都处于同一个应用环境下,系统每次只会用到一种环境的产品.eg:多种数据库支持,多种语言版本的情况可以用
抽象工厂与工厂方法的区别
抽象工厂模式是工厂方法模式的升级版本,用来创建一组相关或者相互依赖的对象。区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
在抽象工厂模式中,有一个产品族的概念:指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。