.NET泛型技巧之打造可複用的抽象工廠

來源:互聯網
上載者:User
技巧   泛型不僅能用來做容器,還能夠提供代碼複用的手段。在泛型的參與下,許多設計就可能更精妙,更具擴充性。今天我就來示範一個利用泛型增強抽象原廠模式。我們知道,抽象工廠(Abstract Factory)模式是將工廠和產品全部抽象化,一個抽象工廠產生一組抽象產品,而一個具體工廠則產生具體產品的一個特定組合。它能夠維持這種相關對象組合的一致性,並使得使用者不需要瞭解工廠和產品的具體實現。傳統的Abstract Factory主要弱點是類型依賴性強,可複用性弱。一個抽象工廠通常是為一個特定需要而設計,通常不能被其他需要抽象工廠的場合使用。而且儘管抽象工廠可以將實際生產任務委派給特定類型的工廠,但這種委派是需要通過自己純程式碼實現的,沒能利用語言所提供的抽象特性。我們今天的任務就是編寫一個不針對特定產品類型和數目的泛型抽象工廠,當你需要特定的抽象工廠時,可隨時複用無需再定義專門的抽象工廠實現。

  我們首先從只產生一個產品的Factory 方法開始,以這作為抽象工廠的原料。很明顯,可以設計這樣一個介面作為Factory 方法的模板:

public interface IFactory<T>
{
 T Create();
}
  這個工廠生產一個T類型的對象。當你實現此工廠時,應該讓T為抽象產品的類型——即產品通用的基類。比如我們可以實現一個採用無參數建構函式來建立對象的OpNewFactory實現:

public class OpNewFactory<TAbstractProduct, TProduct> : IFactory<TAbstractProduct>
where TProduct : TAbstractProduct, new()
{
 public TAbstractProduct Create()
 {
  return new TProduct();
 }
}
  從此例子可以看出,你應該僅實現抽象類別型的IFactory介面,並產生具體類型。現在我們做完了單一產品的Factory 方法模板,就要開始定義生產多個產品的抽象工廠介面了。.NET泛型支援按型別參數個數進行重載,就是說,我們可以定義生產一個、兩個、三個……等多種數目的抽象工廠介面,而使用同一個名字。(汗吧,這就是所謂支援“任意數目”的手法)這裡免不了要拷貝代碼,不過別擔心,純拷貝而已,使用的時候可是非常舒心的哦。我們以生產兩種產品類型的抽象工廠為例介紹。能不能定義成這樣呢?

public interface IAbstractFactory<T1, T2>
{
 T1 Create();
 T2 Create(); //編譯錯誤!!!
}
  哦不!方法不能以傳回型別區分重載,只能靠參數類型重載。然而這裡我們顯然不能用T1和T2作為參數,因為這些方法就是為了生產T1和T2準備的,怎麼能接受它們作為參數呢?難道要命名為Create1和Create2嗎?這很難接受,我們希望生產方法能夠體現產品的類型,怎麼能叫1和2呢。為瞭解決這個問題,我們引入了TypeToken<T>類型,它的定義如下:

public sealed class TypeToken<T>
{
 static private TypeToken<T> instanceValue = new TypeToken<T>();
 static public TypeToken<T> Instance
 {
  get { return instanceValue; }
 }

 private TypeToken() { }
}
  這個類沒有成員,並且每個類型實參只能建立一個執行個體,因此代價極小。但就是這小小的執行個體上帶有其類型實參的類型資訊,因此可以作為判斷函數重載的依據。我們用TypeToken<T>作為區分生產函數重載的依據,實現如下:

public interface IAbstractFactory<T1, T2>
{
 T1 Create(TypeToken<T1> token);
 T2 Create(TypeToken<T2> token);
}
  現在我們針對抽象工廠實現具體工廠。具體工廠就是利用生產每種產品的單一工廠來組合實現。因此你只要有每種類型的單一工廠就可以直接組合產生抽象工廠,而無需定義一個類來做這件事。注意,對每種數目的抽象工廠介面都需要對應產生一個具體工廠的實現,這裡我僅針對產生兩個產品的示範:

public class ConcreteFactory<T1, T2> : IAbstractFactory<T1, T2>
{
 private IFactory<T1> factory1;
 private IFactory<T2> factory2;

 public ConcreteFactory(IFactory<T1> f1, IFactory<T2> f2)
 {
  factory1 = f1;
  factory2 = f2;
 }

 public T1 Create(TypeToken<T1> token)
 {
  return factory1.Create();
 }

 public T2 Create(TypeToken<T2> token)
 {
  return factory2.Create();
 }
}

public static class ConcretFactory
{
 public static ConcreteFactory<T1, T2> NewFactory<T1, T2>(IFactory<T1> f1, IFactory<T2> f2)
 {
  return new ConcreteFactory<T1, T2>(f1, f2);
 }
}
  注意,我又聲明了一個沒有型別參數的ConcretFactory類,用一個靜態方法來產生泛型ConcretFactory的執行個體,這是因為使用泛型方法可以推測型別參數,使得我們可以不必輸入角括弧或Of語句,而泛型類則沒有這個功能。現在大功告成!我們用一個例子來示範這個泛型抽象工廠的工作情況。現在假設我們需要一個生產PC的抽象工廠,需要生產兩種抽象產品:處理器和記憶體。處理器和記憶體的抽象和具體實現如下:

Processor 和 Ram
public abstract class Processor
{
 public abstract string Model { get; }
}

public abstract class Ram
{
 public abstract int Frequency { get;}
}

public class PentiumProcessor : Processor
{
 public override string Model
 {
  get { return "Pentium Extreme Edition 955"; }
 }
}

public class AthlonProcessor : Processor
{
 public override string Model
 {
  get { return "Athlon 64 X2 FX-60"; }
 }
}

public class DDRRam : Ram
{
 public override int Frequency
 {
  get { return 400; }
 }
}

public class DDR2Ram : Ram
{
 public override int Frequency
 {
  get { return 533; }
 }
}
  下面的代碼示範了如何隨心所欲產生想要的抽象工廠介面以及快速從現有單一產品工廠組合成特定的具體工廠實現。

class Program
{
 static IAbstractFactory<Processor, Ram> ComputerFactory(string type)
 {
  if (type == "Intel")
  {
   return ConcretFactory.NewFactory( new OpNewFactory<Processor, PentiumProcessor>(),
new OpNewFactory<Ram, DDR2Ram>());
  }
  else if (type == "AMD")
  {
   return ConcretFactory.NewFactory( new OpNewFactory<Processor, AthlonProcessor>(),
   new OpNewFactory<Ram, DDRRam>());
  }

  //unknown type
  return null;
 }

 static void Main(string[] args)
 {
  //Yield a computer of Intel
  IAbstractFactory<Processor, Ram> factory1 = ComputerFactory("Intel");

  Ram ram1 = factory1.Create(TypeToken<Ram>.Instance);
  Processor cup1 = factory1.Create(TypeToken<Processor>.Instance);

  Console.WriteLine("An Intel Computer");
  Console.WriteLine("CPU Model: {0}", cup1.Model);
  Console.WriteLine("Memory Frequency: {0} MHz", ram1.Frequency);

  Console.WriteLine();

  //Yield a computer of AMD
  IAbstractFactory<Processor, Ram> factory2 = ComputerFactory("AMD");

  Ram ram2 = factory2.Create(TypeToken<Ram>.Instance);
  Processor cup2 = factory2.Create(TypeToken<Processor>.Instance);

  Console.WriteLine("An AMD Computer");
  Console.WriteLine("CPU Model: {0}", cup2.Model);
  Console.WriteLine("Memory Frequency: {0} MHz", ram2.Frequency);
 }
}
  總結:

  我們用泛型技術成功地增強了原本重用性較低的抽象工廠,示範了泛型在提高抽象性和代碼重用方面卓越的價值。

相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。