题目如下:
假设你正在为一家汽车制造公司编写软件。公司生产多种类型的汽车,包括轿车、SUV和卡车。每种汽车都有不同的特点和功能。请设计一个工厂模式,用于创建不同类型的汽车对象。该工厂模式应具有以下要求:工厂类名为 CarFactory,包含一个静态方法 CreateCar,根据传入的参数类型,返回对应类型的汽车对象。汽车类 Car 是一个抽象类,包含一个抽象方法 Drive,用于描述汽车的驾驶行为。轿车类 Sedan 继承自 Car 类,实现了 Drive 方法,在 Drive 方法中输出“驾驶轿车”。SUV 类继承自 Car 类,实现了 Drive 方法,在 Drive 方法中输出“驾驶SUV”。卡车类 Truck 继承自 Car 类,实现了 Drive 方法,在 Drive 方法中输出“驾驶卡车”。使用该工厂模式完成以下操作:在程序入口处,向 CarFactory 的 CreateCar 方法传入参数 "sedan",并将返回的对象存储到 sedanCar 变量中。在 sedanCar 上调用 Drive 方法,观察输出结果。同样地,创建一个 SUV 对象,并调用其 Drive 方法。创建一个 Truck 对象,并调用其 Drive 方法。请根据以上要求实现该工厂模式,并编写相应的代码。
简单工厂实现:
using System;using System.Reflection;namespace Factory{internal class CarFactory{public static T CreateCar<T>() where T : Car, new(){if (typeof(T) == typeof(Sedan))return new Sedan() as T;if (typeof(T) == typeof(SUV))return new SUV() as T;if (typeof(T) == typeof(Truck))return new Truck() as T;throw new ArgumentException("无法创建该类型的汽车对象。");} }}
namespace Factory{public abstract class Car {public abstract void Drive();}}
using System;namespace Factory{internal class Program{static void Main(string[] args){Car sedanCar = CarFactory.CreateCar<Sedan>();sedanCar.Drive();Car suvCar = CarFactory.CreateCar<SUV>();suvCar.Drive();Car truckCar = CarFactory.CreateCar<Truck>();truckCar.Drive();Console.ReadLine();}}}
上述代码给出了抽象基类的基本定义,和泛型工厂的实现方式,以及调用方式。
值得注意的是where T : Car, new()
这个条件:
where T : Car, new()
是对泛型类型参数 T
的约束。这个约束表明泛型类型参数 T
必须满足两个条件:
T
必须是 Car
类或者其派生类:表示 T
必须是 Car
类型或者 Car
类的子类(派生类)。
T
必须具有无参构造函数:通过 new()
约束,表示 T
必须具有一个无参构造函数,即能够使用 new T() 创建 T
的实例。
上述约束的作用是为了确保泛型类型参数 T
在使用过程中是符合要求的。约束 T
必须是 Car
类型或其派生类型,以保证在 CreateCar
方法中创建的对象是 Car
类型或其子类的实例;同时,约束 T
必须具有无参构造函数,以确保可以通过 new T()
的方式来创建 T
的实例。
通过这样的约束,可以确保在调用 CreateCar
方法时,传入的 T
类型参数满足指定的要求,并且能够在方法内部根据 T
的类型来创建相应的对象实例。
工厂模式适用于以下场景:对象创建复杂:当对象的创建涉及到复杂的逻辑判断、依赖关系或者大量的初始化操作时,可以使用工厂模式来封装对象的创建过程。这样可以简化客户端代码,并提供一个统一的入口来创建对象。对象类型不确定:当需要根据不同的条件或者配置来创建不同类型的对象时,可以使用工厂模式。通过工厂模式,可以将对象的创建逻辑从客户端代码中分离出来,降低代码的耦合性。扩展性要求高:当系统中需要添加新的产品或者变化频繁时,使用工厂模式可以方便地扩展和修改代码。通过增加新的具体工厂和产品类,而无需修改已有代码,符合开闭原则。隐藏对象创建细节:当需要隐藏对象创建的细节时,可以使用工厂模式。客户端只需要与工厂接口进行交互,无需关心具体的产品如何创建或实现。总的来说,工厂模式适用于对象创建复杂、对象类型不确定、扩展性要求高以及隐藏对象创建细节的情况。它能够提供灵活、可扩展和易于维护的代码结构。
从代码中我们可以看出CarFactory
这个工厂类是有弊端的,比如每次添加新的汽车对象我们都需要去修改CarFactory
类中的CreateCar
,添加一条新的对象。此时我们可以采用动态工厂,通过反射的形式去创建对象。
using System;using System.Reflection;namespace Factory{internal class CarFactory{public static T CreateCar<T>(string typeName) where T : Car, new(){Type type = GetTypeByName(typeName);if (type != null && typeof(T).IsAssignableFrom(type))return Activator.CreateInstance(type) as T;throw new ArgumentException("无法创建该类型的汽车对象。");}private static Type GetTypeByName(string typeName){return Assembly.GetAssembly(typeof(CarFactory)).GetType($"Factory.{typeName}");}}}
using System;namespace Factory{internal class Program{static void Main(string[] args){// 传递具体类的类型名称作为参数string typeName = "Sedan";Car sedan = CarFactory.CreateCar<Sedan>(typeName);sedan.Drive();// 可以根据需要创建不同类型的汽车对象typeName = "SUV";Car suv = CarFactory.CreateCar<SUV>(typeName);suv.Drive();typeName = "Truck";Car truck = CarFactory.CreateCar<Truck>(typeName);truck.Drive();Console.ReadLine();}}}
这样核心工厂代码我们就不需要修改呢。
通过传进来的typeName
去动态生成实例,其中Assembly.GetAssembly(typeof(CarFactory))
是获取当前类型所处的程序集。Factory.{typeName} 为 命名空间.类
另外 typeof(T).IsAssignableFrom(type)
意思为当前T
类型是否和Type
类型可以进行转换,比如type
是不是T的基类或者派生类。Activator.CreateInstance(type) as T
用于创建实例。