前幾天跟Yuan Ye Pair的時候發現了這個方法
1. 經典的Visitor模式(循環相依性)
public interface Document { void Accept(DocumentVisitor visitor); } public class WordDocument : Document { public void Accept(DocumentVisitor visitor) { visitor.Visit(this); } } public class ExcelDocument : Document { public void Accept(DocumentVisitor visitor) { visitor.Visit(this); } } public interface DocumentVisitor { void Visit(WordDocument wordDocument); void Visit(ExcelDocument excelDocument); }
這裡面 Document依賴於DocumentVisitor, DocumentVisitor依賴於WordDocument和ExcelDocument, 而WrodDocument等又依賴於Document
這樣 Document->DocumentVisitor->WordDocument->Document->...循環相依性
2. 經典的解依賴Visitor模式(Down Cast)
public interface Document { void Accept(DocumentVisitor visitor); } public class WordDocument : Document { public void Accept(DocumentVisitor visitor) { if (visitor is WordDocumentVisitor) { ((WordDocumentVisitor)visitor).Visit(this); } } } public class ExcelDocument : Document { public void Accept(DocumentVisitor visitor) { if (visitor is ExcelDocumentVisitor) { ((ExcelDocumentVisitor)visitor).Visit(this); } } } public interface DocumentVisitor { //空介面, 依賴在這裡斷掉了 } public class ExcelDocumentVisitor : DocumentVisitor { public void Visit(ExcelDocument excelDocument) { } } public class WordDocumentVisitor : DocumentVisitor { public void Visit(WordDocument wordDocument) { } }
3. 消除無聊Accept()方法的Visitor模式
上面的Accept方法幾乎千篇一律, 遵循相同的模式. 裡面無非就是類型計算, 可以利用C#的泛型支援將之消除
public interface Document { void Accept(DocumentVisitor visitor); } public abstract class VisitableDocument<T> : Document where T : VisitableDocument<T> { public void Accept(DocumentVisitor visitor) { var interfaces = visitor.GetType().GetInterfaces(); foreach (var type in interfaces) { if (type.GetGenericArguments().Contains(typeof(T))) { ((DocumentVisitor<T>)visitor).Visit((T)this); } } } } public class WordDocument : VisitableDocument<WordDocument> { //不需要自己實現Accept, 基類已經實現 } public class ExcelDocument : VisitableDocument<ExcelDocument> { //不需要自己實現Accept, 基類已經實現 } public interface DocumentVisitor { //空介面 } public interface DocumentVisitor<T> : DocumentVisitor where T : VisitableDocument<T> { //泛型, 依賴在這裡斷掉了 void Visit(T document); } public class PrintDocumentVisitor : DocumentVisitor<WordDocument>, DocumentVisitor<ExcelDocument> { public void Visit(WordDocument wordDocument) { } public void Visit(ExcelDocument excelDocument) { } }