增加鼠标常数类,将调用者的需求(入参)规范化,防止调用者向工厂下达不能被工厂识别的需求。在MouseFactory的CreateMouse函数中通过反射来生产鼠标实体。这样,在工厂增加新的鼠标种类时,只需要增加实现了IMouse接口的鼠标类,并将该鼠标类的完全限定名维护在鼠标常数中即可。
需要说明的是,常数类只是提供给调用者的一个入参模板,并不能完全限定其传入的参数。虽然通过反射可以让我们在增加新的产品时不必修改工厂,但这只适用于所有产品的实例化逻辑一致的情况下,另外反射的效率要比new的效率低。
非参数化工厂方法(工厂模式)
使用工厂模式去实现一个产品的生产,我们首先需要抽象出这个产品的接口,再分别由不同类型的产品去实现这个接口。之后,我们还需要抽象出一个工厂的接口,再分别由生产不同类型产品的工厂去实现这个接口,供调用者使用。
public interface IMouse { string GetBrand(); } public class LogitechMouse : IMouse { public string GetBrand() { return "罗技-Logitech"; } } public class RazeMouse : IMouse { public string GetBrand() { return "雷蛇-Raze"; } } public interface IMouseFactory { IMouse CreateMouse(); } public class LogitechMouseFactory : IMouseFactory { public IMouse CreateMouse() { return new LogitechMouse(); } } public class RazeMouseFactory : IMouseFactory { public IMouse CreateMouse() { return new RazeMouse(); } } class Program { static void Main(string[] args) { //创建工厂 IMouseFactory logitechFactory = new LogitechMouseFactory(); IMouseFactory razeFactory = new RazeMouseFactory(); //通过工厂生产实体 IMouse mouseA = logitechFactory.CreateMouse(); IMouse mouseB = razeFactory.CreateMouse(); Console.WriteLine($"MouseA的品牌是:{mouseA.GetBrand()}"); Console.WriteLine($"MouseB的品牌是:{mouseB.GetBrand()}"); Console.ReadKey(); } }示例中IMouseFactory的CreateMouse函数就是所谓的工厂方法,调用者通过IMouseFactory的子类去实例化IMouseFactory接口本身(多态,面向对象的基本特征之一),再调用工厂方法去实例化相应鼠标实体。
这样的好处是,在工厂增加新的鼠标种类时,只需要增加实现了IMouse接口的鼠标类和负责生产这个鼠标的实现了IMouseFactory接口的工厂类(承载了工厂方法的类,如示例中的LogitechMouseFactory )即可。在符合开闭原则的同时避免了简单工厂中不能完全将调用者传入的参数规范化导致的工厂不能正确生产对应的鼠标实体的问题,并且new的效率要比反射效率高。
虽然在工厂模式中解决了简单工厂的一些弊端,但是随着鼠标种类的增加,对应的工厂数量也会日益庞大。在工厂模式中,这是不可避免的一个问题。
总结工厂方法模式,简单的理解就是将一系列对象的实例化逻辑封装到一个或几个从同一接口派生的类中,使调用者更专注于面向接口的开发而不必过于关心具体的实现,给予了我们很大的灵活性。工厂的指定即可以是静态的(编译时指定)也可以是动态的(运行时指定)。它是符合开闭原则的,方便了我们对于程序的扩展及维护。
但在简单工厂(参数化工厂方法)下,增加了程序对工厂类的依赖,一旦工厂类不能正常使用,会有较大的影响范围。而在工厂模式(非参数化工厂方法)中,虽然减少了程序对某个工厂类的依赖,但随着产品的增加,工厂数量也会日益庞大。
无论是简单工厂还是工厂模式,在产品的基数少时,使用该模式反而会增加我们的工作量。所以,并不是所有的场景下都适用。
以上,就是我对工厂方法的理解,希望对你有所帮助。
示例源码:https://gitee.com/wxingChen/DesignPatternsPractice