惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
Stack Overflow Blog
Stack Overflow Blog
人人都是产品经理
人人都是产品经理
The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
Vercel News
Vercel News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Y
Y Combinator Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
Google DeepMind News
Google DeepMind News
D
DataBreaches.Net
博客园 - 司徒正美
B
Blog RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
L
LangChain Blog

博客园 - chelsea

Performance Tuning Technique: Ultra-Fast ASP.Net 书摘 ASP.Net 备忘 On Extension Method: 扩展方法该如何使用 REST on ASP.Net MVC (and Future) IoC 问题域 Log 问题域 Validation 问题域 代码的物理组织 C#代码组织: project over folder ORM问题域 Web开发问题域 向 Spring.Net 提交的建议被采纳并实现了 开源.Net中文分词组件 [导入]C# 备忘录 The C# Programming Language Notes II [导入]C++/CLI:被忽视的集成技术 DNN4 (DotNetNuke) 备忘录 持续集成 .Net手册 The Programming Language Idioms
C#泛型: 消除Visitor模式的循环依赖, 以及无聊的Accept方法
chelsea · 2010-03-15 · via 博客园 - chelsea

Posted on 2010-03-15 23:29  chelsea  阅读(952)  评论()    收藏  举报

前几天跟Yuan Ye Pair的时候发现了这个方法 

1. 经典的Visitor模式(循环依赖)

classic visitor pattern

 1     public interface Document
 2     {
 3         void Accept(DocumentVisitor visitor);
 4     }
 5 
 6     public class WordDocument : Document
 7     {
 8         public void Accept(DocumentVisitor visitor)
 9         {
10             visitor.Visit(this);
11         }
12     }
13 
14     public class ExcelDocument : Document
15     {
16         public void Accept(DocumentVisitor visitor)
17         {
18             visitor.Visit(this);
19         }
20     }
21 
22     public interface DocumentVisitor
23     {
24         void Visit(WordDocument wordDocument);
25         void Visit(ExcelDocument excelDocument);
26     }
27 

这里面 Document依赖于DocumentVisitor, DocumentVisitor依赖于WordDocument和ExcelDocument, 而WrodDocument等又依赖于Document

这样 Document->DocumentVisitor->WordDocument->Document->...循环依赖

2. 经典的解依赖Visitor模式(Down Cast)

decouple visitor (dynamic cast))

 1     public interface Document
 2     {
 3         void Accept(DocumentVisitor visitor);
 4     }
 5 
 6     public class WordDocument : Document
 7     {
 8         public void Accept(DocumentVisitor visitor)
 9         {
10             if (visitor is WordDocumentVisitor)
11             {
12                 ((WordDocumentVisitor)visitor).Visit(this);
13             }
14         }
15     }
16 
17     public class ExcelDocument : Document
18     {
19         public void Accept(DocumentVisitor visitor)
20         {
21             if (visitor is ExcelDocumentVisitor)
22             {
23                 ((ExcelDocumentVisitor)visitor).Visit(this);
24             }
25         }
26     }
27 
28     public interface DocumentVisitor
29     {
30         //空接口, 依赖在这里断掉了
31     }
32 
33     public class ExcelDocumentVisitor : DocumentVisitor
34     {
35         public void Visit(ExcelDocument excelDocument)
36         {
37             
38         }
39     }
40 
41     public class WordDocumentVisitor : DocumentVisitor
42     {
43         public void Visit(WordDocument wordDocument)
44         {
45         }
46     }
47 

 3. 消除无聊Accept()方法的Visitor模式

上面的Accept方法几乎千篇一律, 遵循相同的模式. 里面无非就是类型计算, 可以利用C#的泛型支持将之消除

remove Accept from all subclasses

 1     public interface Document
 2     {
 3         void Accept(DocumentVisitor visitor);
 4     }
 5 
 6     public abstract class VisitableDocument<T> : Document where T : VisitableDocument<T>
 7     {
 8         public void Accept(DocumentVisitor visitor)
 9         {
10             var interfaces = visitor.GetType().GetInterfaces();
11 
12             foreach (var type in interfaces)
13             {
14                 if (type.GetGenericArguments().Contains(typeof(T)))
15                 {
16                     ((DocumentVisitor<T>)visitor).Visit((T)this);
17                 }
18             }
19         }
20     }
21 
22     public class WordDocument : VisitableDocument<WordDocument>
23     {
24         //不需要自己实现Accept, 基类已经实现
25     }
26 
27     public class ExcelDocument : VisitableDocument<ExcelDocument>
28     {
29         //不需要自己实现Accept, 基类已经实现
30     }
31 
32     public interface DocumentVisitor
33     {
34         //空接口
35     }
36 
37     public interface DocumentVisitor<T> : DocumentVisitor where T : VisitableDocument<T>
38     {
39         //泛型, 依赖在这里断掉了
40         void Visit(T document);
41     }
42 
43     public class PrintDocumentVisitor : DocumentVisitor<WordDocument>, DocumentVisitor<ExcelDocument>
44     {
45         public void Visit(WordDocument wordDocument)
46         {
47         }
48 
49         public void Visit(ExcelDocument excelDocument)
50         {
51         }
52     }
53