首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

設計模式之旅:以 C# Generics 改良策略模式

     編輯:關於C#

摘要

前文使用 C++ template 改良策略模式,本文改用 C# 2.0 引入的泛型來達成相同目標。

問題背景

在策略模式中,為讓策略完整存取物件的 public 方法/屬性,常傳遞 this 給策略:

public void drawShape() {
 this.shape.draw(this);
}

介面因此必須定義為:

interface IShape {
 void draw(Grapher grapher);
}

完整程式碼見下:

策略模式傳統寫法類別圖
/**/*
 (C) OOMusou 2007 https://oomusou.cnblogs.com

Filename : DP_StrategyPattern3_polymorphism_this.cs
Compiler : Visual Studio 2005 / C# 2.0
Description : Demo how to use Strategy Pattern with this
Release : 04/07/2007 1.0
*/
using System;

interface IShape {
 void draw(Grapher grapher);
}

class Grapher {
 private IShape shape;
 private string text;

 public Grapher() { }
 public Grapher(IShape shape) : this(shape, "Hello Shape!!") { }
 public Grapher(IShape shape, string text) {
 this.shape = shape;
 this.text = text;
 }

 public void drawShape() {
 this.shape.draw(this);
 }

 public void setShape(IShape shape, string text) {
 this.text = text;
 this.shape = shape;
 }

 public string getText () {
 return this.text;
 }
}

class Triangle : IShape {
 public void draw(Grapher grapher) {
 Console.WriteLine("Draw {0:s} in Triangle", grapher.getText());
 }
}

class Circle: IShape {
 public void draw(Grapher grapher) {
 Console.WriteLine("Draw {0:s} in Circle", grapher.getText());
 }
}

class Square : IShape {
 public void draw(Grapher grapher) {
 Console.WriteLine("Draw {0:s} in Square", grapher.getText());
 }
}

class main {
 public static void Main() {
 Grapher theGrapher = new Grapher(new Square());
 theGrapher.drawShape();

 theGrapher.setShape(new Circle(), "Hello C#!!");
 theGrapher.drawShape();
 }
}

執行結果:

Draw Hello Shape!! in Square
Draw Hello C#!! in Circle

潛在問題

IShape 介面綁定 Grapher 型別,若未來新增 Painter 類別(與 Grapher 無繼承關係)也想使用同樣策略,將無法實作,因為介面已鎖定型別。

以 Generics 解決

將介面改為泛型:

interface IShape<T> {
 void draw(T grapher);
}

實作類別亦需修改:

class Triangle<T> : IShape<T> where T : IGrapher {
 public void draw(T grapher) {
 Console.WriteLine("Draw {0:s} in Triangle", grapher.getText());
 }
}

C# 的 where 關鍵字用於限制泛型型別參數(稱為 constraint),這是 C# 泛型與 C++ template 最大不同:C# 採「有限制的泛型」或「基於介面的泛型」(強型別泛型),泛型必須受限於介面;C++ 則無此限制。

where T : IGrapher 表示泛型 T 必須實作 IGrapher 介面。因為策略會呼叫 getText(),故定義:

interface IGrapher {
 string getText();
}

未來若 Painter 也想使用策略,只需實作 IGrapher 即可。

完整程式碼

泛型策略模式類別圖
/**/*
 (C) OOMusou 2007 https://oomusou.cnblogs.com

Filename : DP_StrategyPattern3_polymorphism_this.cs
Compiler : Visual Studio 2005 / C# 2.0
Description : Demo how to use Strategy Pattern with this by Generic
Release : 04/07/2007 1.0
*/
using System;

interface IGrapher {
 string getText();
}

interface IShape<T> {
 void draw(T grapher);
}

class Grapher : IGrapher {
 private IShape<Grapher> shape;
 private string text;

 public Grapher() { }
 public Grapher(IShape<Grapher> shape) : this(shape, "Hello Shape!!") { }
 public Grapher(IShape<Grapher> shape, string text) {
 this.shape = shape;
 this.text = text;
 }

 public void drawShape() {
 this.shape.draw(this);
 }

 public void setShape(IShape<Grapher> shape, string text) {
 this.text = text;
 this.shape = shape;
 }

 public string getText () {
 return this.text;
 }
}

class Triangle<T> : IShape<T> where T : IGrapher {
 public void draw(T grapher) {
 Console.WriteLine("Draw {0:s} in Triangle", grapher.getText());
 }
}

class Circle<T> : IShape<T> where T : IGrapher{
 public void draw(T grapher) {
 Console.WriteLine("Draw {0:s} in Circle", grapher.getText());
 }
}

class Square<T> : IShape<T> where T : IGrapher {
 public void draw(T grapher) {
 Console.WriteLine("Draw {0:s} in Square", grapher.getText());
 }
}

class main {
 public static void Main() {
 Grapher theGrapher = new Grapher(new Square<Grapher>());
 theGrapher.drawShape();

 theGrapher.setShape(new Circle<Grapher>(), "Hello C#!!");
 theGrapher.drawShape();
 }
}

執行結果:

Draw Hello Shape!! in Square
Draw Hello C#!! in Circle

結語與比較

C# 泛型優勢在於可指定多重限制:

where T : IGrapher, IPainter

這比單一介面的多型更強,可視為「更強的多型」。但 C# 泛型基於介面/類別,稱為「強型別泛型」,好處是編譯期發現錯誤、支援 IntelliSense;C++ 屬「弱型別泛型」,常在執行期才發現錯誤。C# 泛型較穩定,但限制較多,較無「泛型味道」。作者個人偏好 C++ template 的自由度。

即便如此,C# 泛型仍可視為「更強的多型」,許多原本用多型的設計,可考慮改用泛型擴大適用範圍。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved