太仓做网站的,运营商查浏览网站,牡丹江网络推广公司,刷死粉网站推广简介 工厂模式#xff08;Factory Pattern#xff09;是最常用的设计模式之一。这种类型的设计模式属于创建型模式#xff0c;它提供了一种创建对象的最佳方式。在工厂模式中#xff0c;我们在创建对象时不会对客户端暴露创建逻辑#xff0c;而是通过使用一个共同的接口来… 简介 工厂模式Factory Pattern是最常用的设计模式之一。这种类型的设计模式属于创建型模式它提供了一种创建对象的最佳方式。在工厂模式中我们在创建对象时不会对客户端暴露创建逻辑而是通过使用一个共同的接口来指向新创建的对象。分类 工厂模式可以分为三种其中简单工厂一般不被认为是一种设计模式可以将其看成是工厂方法的一种特殊。简单工厂工厂方法抽象工厂场景分析 平凡枯燥的文字总是让人看得想睡觉接下来我们用几个情景案例来进行分析简单工厂直接通过一个Factory【工厂类】类创建多个实体类的构造方式。时间2021年2月19日 地点教室 人物学生小白、老师、大佬黑皮小白是一名大二的计算机系学生懒惰不爱学习。今天早晨第一节课就因为睡懒觉迟到被老师逮个正着这节课还正好是小白最头疼的上机课C#设计模式”。这不课堂上到一半老师就开始提问小白“光荣”的成为了老师的点名对象。老师笑着说道“小白请你解答一下屏幕上的问题。”题目请使用c#、java、python、php或其他任一面向对象编程语言实现输入俩个合法数字和一个合法符号输出对应结果的功能。小白一看这算什么题目这么简单看我不手到擒来伴随着双手噼里啪啦一顿敲击声音屏幕上出现一串编码。**Calculator操作类 ** public class Calculator{public double GetResult(double A, double B, string operate){double result 0d;switch (operate){case : result A B;break;case -:result A - B;break;case *:result A * B;break;case /:result A / B;break;default: break;}return result;}}
客户端代码 class Program{static void Main(string[] args){Console.WriteLine(请输入数字A);string a Console.ReadLine();Console.WriteLine(请输入数字B);string b Console.ReadLine();Console.WriteLine(请选择操作符号(、-、*、/));string operate Console.ReadLine();Calculator box new Calculator();double result box.GetResult(Convert.ToDouble(a), Convert.ToDouble(b), operate);Console.WriteLine(result);Console.ReadKey();}}
小白”老师我写好了“老师不错写的很好。使用到了面向对象三大特性中的封装将计算方法封装成了一个计算类多个客户端可以复用这个类。但是这其中也有不少的问题哪位同学来回答一下。黑皮”小白同学写的代码有俩处问题。1、如果输入A10B0,程序就会报错没有做输入的有效性验证2、如果操作符号不按照规定的输入 也会导致报错“老师”黑皮同学回答的非常好但是这都只是针对代码业务逻辑错误的描述。有没有谁可以看出更加深层次的内容。“黑皮”老师你给点提示吧。“老师”这个可以会有点隐蔽老师就给出一点提示。如果我们增加一个新的运算怎么办“小白立即回答到”在switch中增加一个新的分支就可以了“。老师”这样当然是没有错误的但是问题在于我只是增加了一个新的运算符号却需要让加减乘除所有的运算都参加编译如果在修改的过程中不小心修改了其他的代码例如把号改成了-号那不是很糟糕这就违背了开闭原则【对扩展开放对修改关闭】“小白挠一挠头问道”开闭原则这是什么“老师”这就是你不认真听课落下的内容回去好好补习。黑皮同学不知道你Get到了老师的点没有“黑皮”我知道应该如何修改了。小白实现了面向对象三大特性之一的封装其实就是将其他俩个特性一起使用就可以完成老师要的功能“小白”多态和继承“黑皮”是的等我改完你再看程序就应该有感觉了“ public class Operate{public double NumberA { get; set; }public double NumberB { get; set; }public virtual double GetResult(){return 0;}}public class OperateAdd : Operate{public override double GetResult(){return this.NumberA this.NumberB;}}public class OperateSub : Operate{public override double GetResult(){return this.NumberA - this.NumberB;}}
简单工厂 public class OperateFactory{public static Operate GetOperateFactory(string operate){Operate fac null;switch (operate){case :fac new OperateAdd();break;case -:fac new OperateSub();break;case *:fac new OperateMul();break;case /:fac new OperateDiv();break;default:break;}return fac;}}
黑皮”首先是一个运算类里面有俩个Number属性和一个虚方法GetResult()。加减乘除四个方法作为运算类的子类继承继承后重写GetResult()方法调用基类的A和B公有属性进行不同的数学运算。“黑皮”然后定义一个简单工厂静态方法传入操作符参数得到实际的业务处理类客户端得到处理类后对参数赋值。最后一步你应该知道怎么做了吧“小白”我懂了那客户端这么调用就可以了“。 static void Main(string[] args){Console.WriteLine(请选择操作符号(、-、*、/));string operateStr Console.ReadLine();Operate operate OperateFactory.GetOperateFactory(operateStr);operate.NumberA 10;operate.NumberB 4;double result operate.GetResult();Console.WriteLine(result);Console.ReadKey();}
老师”看来俩位同学都已经掌握了简单工厂的使用接下来我提问几个问题便于大家更快的掌握这种设计模式“老师”如果我们要修改除方法的逻辑增加被除数为0的逻辑应该怎么做“小白”直接修改OperateDiv类这不会对其他造成影响“老师”如果我们要新增一个开根运算应该怎么做“小白”添加一个新的类Operate开根类里面描述开根的逻辑。在工厂方法中将新的操作符添加进去即可。新增的操作单独一个类也不会对其他方法体造成影响“。小白”那客户端需要做什么改变吗“老师”客户端要做什么改变客户端只要处理好自己的事情就可以了“是的客户端不关心工厂创建了什么工厂是一个黑盒子。客户端只要传入参数工厂负责将内容生产后【实例化类的过程】给客户端即可。优/缺点简单工厂模式的工厂类一般是使用静态方法通过接收的参数不同来返回不同的对象实例。不修改代码的话是无法扩展的 优点客户端可以免除直接创建产品对象的责任而仅仅是“消费”产品。简单工厂模式通过这种做法实现了对责任的分割 缺点由于工厂类集中了所有实例的创建逻辑违反了高内聚责任分配原则将全部创建逻辑集中到了一个工厂类中它所能创建的类只能是事先考虑到的如果需要添加新的类则就需要改变工厂类了工厂方法时间2021年2月19日下午 地点教室 人物学生小白、老师、大佬黑皮老师”我们紧接着上午的设计模式继续上午我们讲的是简单工厂下午我们讲下一个内容工厂方法。工厂方法和简单工厂其实大同小异唯一的区别就在于每一个实现抽象类的实例也叫做产品即上午定义的加减乘除四个子类都有一个对应的工厂去创建。同学们了解一下老师说话的内容然后寻找一个场景编码实现一下。最快完成的有课堂奖励”....几分钟过去了.....小白“老师我完成了。”老师“好的那我们请小白同学说明一下场景和实现的方式。”我设计的是以水果作为场景的模式。1、定义一个抽象类Fruit.cs这个类定义俩个抽象方法printfColor()和printfName()。2、实现俩种不同的水果分别继承此抽象类并复写抽象方法。3、定义一个工厂接口定义接口方法createFruit()4、实现俩个不同的工厂分别实现水果实例的创建。水果抽象类 public abstract class Fruit{public abstract void PrintfColor();public abstract void PrintfName();}public class Apple : Fruit{public override void PrintfColor(){Console.WriteLine(红色);}public override void PrintfName(){Console.WriteLine(苹果);}}
工厂接口 public interface IFruitFactory{Fruit CreateFruit();}public class AppleFactory : IFruitFactory{public Fruit CreateFruit(){return new Apple();}}
客户端实现 //苹果工厂IFruitFactory appleFac new AppleFactory();Fruit apple appleFac.CreateFruit();apple.PrintfColor();apple.PrintfName//橘子工厂IFruitFactory orangeFac new OrangeFactory();Fruit orage orangeFac.CreateFruit();orage.PrintfColor();orage.PrintfName();
老师“看来小白同学已经对上午的内容有了一个充分的了解果然好好上课才能够学习到新的知识。逃课是没有益处的”老师“只是这样的案例太过简单可能其他同学不是很能理解为什么要这样 我来举一个实际场景的案例方便大家理解。在实际的工作过程中我们总会用到日志组件例如Nlog,Log4net这种第三方组件这种组件都支持可配置化的多源输出。当我们在配置文件json/xml中增加一个“输出到控制台的参数”程序 就会将内容输出到控制台当配置一个输入到文件的参数程序就会将内容输出到指定的文件。这种场景的实现其实就是一种典型的工厂方法。下面我来分析一下过程”1、读取配置文件json/xml2、获取所有的配置方式循环遍历3、判断配置类型如果是输入到文件的配置。new一个文件日志工厂将配置信息作为参数传递便于后期方法调用如果是输入到控制台的配置。new一个日志工厂也是做同样的操作4、每一个工厂只管理自己的事情但是应该都拥有日志输出这个接口。5、当上层调用打印方法时候循环遍历所有的工厂调用接口的日志输出输出方法优/缺点工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。在同一等级结构中支持增加任意产品 优点允许系统在不修改具体工厂角色的情况下引进新产品 缺点由于每加一个产品就需要加一个产品工厂的类增加了额外的开发量抽象工厂抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比抽象工厂模式中的具体工厂不只是创建一种产品它负责创建一族产品。时间2021年2月20日上午 地点教室 人物学生小白、老师、黑皮新的一天又开始了“设计模式”课程在小白的眼中好像没有那么复杂了今天小白早早地就到了教室准备迎接老师新的鞭策。老师”同学们早上好今天我们继续昨日的课程。昨天讲的是工厂方法今天我们在此基础上做一点改进看看又有什么新的变化。小白同学学习热情很高嘛现在都知道坐在第一排了。不错不错值得鼓励”小白”嘻嘻“老师“好那开始今天的课程。今天要讲的模式是抽象工厂模式。通过和工厂模式做比较同学们可以比较清晰的发现这俩都之间的区别。我们用昨天小白同学的例子继续开拓。”此时有苹果和橘子俩个产品分别对应苹果工厂和橘子工厂。这是工厂方法的体现。可是如果有3个不同的工厂他们分别都生产苹果和橘子呢。小白“恩...那就多建立几个工厂。每个产品分别对应不同的工厂应该是这样的一个结构每一个工厂分别对应生产产品的类”AA_苹果工厂.csA_橘子工厂.csBB_苹果工厂.csB_橘子工厂.csCC_苹果工厂.csC_橘子工厂.cs老师“这样的方式当然是可以的可以如果我有10个工厂呢难道我们要建立10*220个类吗这样程序的复杂度就是直线上升不利于维护。”小白“那怎么办呢用老师你说的那种抽象工厂吗如果用又应该怎么做呢”老师“是的在这样的场景下抽象工厂是最能匹配的设计模式。其实做法非常简单对昨天的代码进行一些修改即可”水果抽象类新增一个Name属性方便后期打印不同的工厂。 public abstract class Fruit{public string Name { get; set; }public abstract void PrintfColor();public abstract void PrintfName();}public class Apple : Fruit{public Apple(string name){this.Name name;}public override void PrintfColor(){Console.WriteLine(this.Name 红色);}public override void PrintfName(){Console.WriteLine(this.Name 苹果);}}
工厂接口老师“这一处的改动就比较明显。原来的接口中方法输出唯一的产品——因为之前每一个工厂只生产一件产品。现在输出俩个产品即继承工厂接口的类必须实现生产苹果和橘子的方法。这样的好处在于每一个工厂负责管理自己产品的实现避免了每一个产品都需要创建一个工厂的操作。“解释工厂生产苹果和橘子。当有多个工厂的时候每一个工厂都实现生产苹果和橘子。而不是生产A厂苹果需要一个工厂实现类生产B厂苹果又需要一个。如下所示旧模式AA_苹果工厂.A_橘子工厂BB_苹果工厂B_橘子工厂CC_苹果工厂新模式A 工厂苹果/橘子B 工厂苹果/橘子C 工厂苹果/橘子老师“这样复杂度由原来的6变成了3。”小白:我明白了又学习到了新的东西。 public interface IFruitFactory{Fruit CreateApple(string name);Fruit CreateOrange(string name);}public class AFactory : IFruitFactory{public Fruit CreateApple(string name){return new Apple(name);}public Fruit CreateOrange(string name){return new Orange(name);}}
客户端实现 IFruitFactory fac new AFactory();Fruit a_Apple fac.CreateApple(a工厂);Fruit a_Orange fac.CreateOrange(a工厂);a_Apple.PrintfName();a_Orange.PrintfName();IFruitFactory b_fac new BFactory();Fruit b_Apple b_fac.CreateApple(b工厂);Fruit b_Orange b_fac.CreateOrange(b工厂);b_Apple.PrintfName();b_Orange.PrintfName();
小白“可是在什么样的场景下用这种模式呢我好像一下子想不到”老师“抽象工厂的使用相对来说比较少但也不是没有。我举一个例子在后端开始中我们有各种的组件【按钮抽屉导航栏】等等这些组件有对应的皮肤对皮肤的开发就是抽象工厂的实现。工厂接口是对每个组件的定义每个皮肤就是一个工厂的实现。如果要切换皮肤只需要实例化不同的工厂即可。”小白“哦。就和游戏中的皮肤切换一样吗”老师“你也可以这样理解设计模式只是一种通用解决方案可以应用在不同的场景下大家可以挑最适应自己最好理解的场景下手。”下课铃声又响起了老师“好了这节课就到这里。下节课我们讲其他的设计模式希望大家准时听讲。”优/缺点抽象工厂是应对产品族概念的。应对产品族概念而生增加新的产品线很容易但是无法增加新的产品。比如每个汽车公司可能要同时生产轿车、货车、客车那么每一个工厂都要有创建轿车、货车和客车的方法 优点向客户端提供一个接口使得客户端在不必指定产品具体类型的情况下创建多个产品族中的产品对象 缺点增加新的产品等级结构很复杂需要修改抽象工厂和所有的具体工厂类对“开闭原则”的支持呈现倾斜性推荐阅读Redis工具收费后新的开源已出现GitHub上Star最高的工程师技能图谱中国程序员最容易发错的单词推荐!!! Markdown图标索引网站END 欢迎关注公众号 程序员工具集 ???????? 致力于分享优秀的开源项目、学习资源 、常用工具回复关键词“关注礼包”送你一份最全的程序员技能图谱。