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

推荐订阅源

D
Docker
爱范儿
爱范儿
Vercel News
Vercel News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Martin Fowler
Martin Fowler
博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tailwind CSS Blog
Blog — PlanetScale
Blog — PlanetScale
博客园 - 【当耐特】
人人都是产品经理
人人都是产品经理
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - Franky
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
H
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
G
Google Developers 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