請修改本章最後完成的那個比較適於工程應用的工廠類型,使其支持含參數的構造函數
分析:
1、本著OCP原則,我們不對原有Factory<T> 進行修改,而是通過繼承對其進行擴展
2、繼續采用.NET Framework自帶的Activator提供對於帶參數構造函數的支持
3、為了與原有Factory<T>的方法簽名作區別,我們在新的接口中要求只有明確聲明為object[]的數組才作為構造函數參數
參考答案
1、為了不引起其歧義,首先修改引用的命名空間
using System;
using F = MarvellousWorks.PracticalPattern.FactoryMethod;
using Microsoft.VisualStudio.TestTools.UnitTesting;
2、定義新的工廠接口和具體工廠類型
interface IFactory : F.IFactory
{
#region factory method
TTarget Create<TTarget>(object[] parametes);
TTarget Create<TTarget>(string name, object[] parametes);
#endregion
}
class Factory : F.Factory, IFactory
{
public TTarget Create<TTarget>(object[] parametes)
{
return (TTarget)Activator.CreateInstance(registry[typeof(TTarget)], parametes);
}
public TTarget Create<TTarget>(string name, object[] parametes)
{
return (TTarget)Activator.CreateInstance(registry[typeof(TTarget), name], parametes);
}
}
3、編寫單元測試驗證
[TestMethod]
public void CreateInstance()
{
var factory = new Factory()
.RegisterType<IFruit, Apple>()
.RegisterType<IFruit, Orange>("o")
.RegisterType<IVehicle, Bicycle>()
.RegisterType<IVehicle, Bicycle>("a")
.RegisterType<IVehicle, Train>("b")
.RegisterType<IVehicle, Car>("c")
.RegisterType<IEntry, EntryWithName>()
.RegisterType<IEntry, EntryWithName>("n")
.RegisterType<IEntry, EntryWithNameAndAgeAndTitle>("nat");
#region 構造函數無參數的類型
Assert.IsInstanceOfType(factory.Create<IFruit>(), typeof(Apple));
Assert.IsInstanceOfType(factory.Create<IFruit>("o"), typeof(Orange));
Assert.IsInstanceOfType(factory.Create<IVehicle>(), typeof(Bicycle));
Assert.IsInstanceOfType(factory.Create<IVehicle>("a"), typeof(Bicycle));
Assert.IsInstanceOfType(factory.Create<IVehicle>("b"), typeof(Train));
Assert.IsInstanceOfType(factory.Create<IVehicle>("c"), typeof(Car));
#endregion
#region 構造函數帶參數的類型
// 轉換為新的擴展接口形式
var f = (IFactory) factory;
// 使用擴展的功能
var e1 = f.Create<IEntry>(new object[] { "joe" });
Assert.IsInstanceOfType(e1, typeof(EntryWithName));
Assert.AreEqual<string>("joe", ((EntryWithName) e1).Name);
var e2 = f.Create<IEntry>("nat", new object[] { "joe", 20});
Assert.IsInstanceOfType(e2, typeof(EntryWithNameAndAgeAndTitle));
Assert.AreEqual<string>("joe", ((EntryWithName)e2).Name);
Assert.AreEqual<int>(20, ((EntryWithNameAndAgeAndTitle)e2).Age);
Assert.AreEqual<string>(EntryWithNameAndAgeAndTitle.DefaultTitle, ((EntryWithNameAndAgeAndTitle)e2).Title);
#endregion
}