在作为MVC引擎的MvcEngine类中,我们定义了四个工厂方法(GetListener、GetControllerActivator、GetControllerExecutor和GetViewRenderer)来提供上述这四种类型的对象。这四个工厂方法均为具有默认实现的虚方法,它们默认提供上述四种类型的对象。在用于启动引擎的Start方法中,我们利用这些工厂方法提供的对象来具体完成请求处理流程的各个核心环节。
public class MvcEngine { public void Start(Uri address) { while (true) { Request request = this.GetListener().Listen(address); Task.Run(() => { Controller controller = this.GetControllerActivator() .ActivateController(request); View view = this.GetControllerExecutor() .ExecuteController(controller); this.GetViewRenderer().RenderView(view); }); } } protected virtual Listener GetListener() { return new Listener(); } protected virtual ControllerActivator GetControllerActivator() { return new ControllerActivator(); } protected virtual ControllerExecutor GetControllerExecutor() { return new ControllerExecutor(); } protected virtual ViewRenderer GetViewRenderer() { return new ViewRenderer(); } }
对于具体的应用程序来说,如果需要对请求处理的某个环节进行定制,它需要将定制的操作实现在对应类型(Listener、ControllerActivator、ControllerExecutor和ViewGenderer)的派生类中。在MvcEngine的派生类中,我们需要重写对应的工厂方法来提供被定制的对象。 比如上面提及的以单例模式提供目标Controller对象的实现就定义在SingletonControllerActivator类中,我们在派生于MvcEngine的FoobarMvcEngine类中重写了工厂方法GetControllerActivator使其返回一个SingletonControllerActivator对象。
public class SingletonControllerActivator : ControllerActivator { public override Controller ActivateController(Request request) { <<省略实现>> } } public class FoobarMvcEngine : MvcEngine { protected override ControllerActivator GetControllerActivator() { return new SingletonControllerActivator(); } }
上面我们采用工厂方法模式对MVC框架进行了重新设计,右图清晰地展示了该框架以MvcEngine为核心的相关组件之间的相互关系,同时也体现了采用派生MvcEngine(FoobarMvcEngine)具体的应用是如何通过重写工厂方法(GetControllerActivator)对框架实施定制的。
抽象工厂(Abstract Factory)
虽然工厂方法和抽象工厂均提供了一个“生产”对象实例的工厂,但是两者在设计上却有本质的不同。工厂方法利用定义在某个类型的抽象方法或者虚方法实现了针对单一对象提供方式的抽象,而抽象工厂在利用一个独立的接口或者类来实现对一组相关对象提供的抽象。
具体来说,我们需要定义一个独立的工厂接口或者抽象工厂类,并在其中定义多个的工厂方法来提供“同一系列”的多个相关对象。如果希望抽象工厂具有一组默认的“产出”,我们也可以将一个未被封闭的具体类作为抽象工厂,以虚方法形式定义的工厂方法将默认的对象作为返回值。我们根据实际的需要通过实现工厂接口或者继承抽象工厂类(不一定是抽象类)定义具体工厂类来提供一组定制的系列对象。
现在我们采用抽象工厂模式来改造我们的MVC框架。如下面的代码片段所示,我们定义了一个实例类EngineFactory作为创建MvcEngine所需四种对象(Listener、ControllerActivator、ControllerExecutor和ViewGenderer)的抽象工厂,定义其中的四个工厂方法的返回值体现了工厂默认的产出。我们在创建MvcEngine对象可以提供一个具体的EngineFactory对象(如果没有显式指定,MvcEngine默认使用的是一个自动创建的EngineFactory对象)。在用于启动引擎的Start方法中,MvcEngine利用EngineFactory来获取相应的对象协作完整对请求的处理流程。 对于我们采用抽象工厂改造后的MVC框架,以MvcEngine为核心的相关组件之间的关系体现在如左图所示的UML中。
public class EngineFactory { public virtual Listener GetListener() { return new Listener(); } public virtual ControllerActivator GetControllerActivator() { return new ControllerActivator(); } public virtual ControllerExecutor GetControllerExecutor() { return new ControllerExecutor(); } public virtual ViewRenderer GetViewRenderer() { return new ViewRenderer(); } } public class MvcEngine { public EngineFactory Factory { get; private set; } public MvcEngine(EngineFactory factory = null) { this.Factory = factory ?? new EngineFactory(); } public void Start(Uri address) { while (true) { Request request = this.Factory.GetListener().Listen(address); Task.Run(() => { Controller controller = this.Factory.GetControllerActivator() .ActivateController(request); View view = this.Factory.GetControllerExecutor() .ExecuteController(controller); this.Factory.GetViewRenderer().RenderView(view); }); } } }