- 1、本文档共5页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
绑定子类的泛型基类,反模式?
这次总结一个个人认为的反模式: 绑定子类的泛型层基类”,这个模式在一些著名的框架中
也见到过,如果 CSLA、BlogEngine 。我自己在原来的写的框架中,也用到过。
当然了,个人认为是反模式,各们同仁并不一定这样认为,仁者见仁,智者见智了。不过我 好几次都是受尽折磨,所以决定写出来给大家分享下心得。
模式介绍
层基类是MF提出的一个基本模式,详见:《 Layer Supertype 》。这种模式在经典的 层次型架构设计的实现中,是极其重要的。我相信, 大家一般在做三层架构时,不可能不给
出基类的。至少我没见过。:)
?NET2.0推出后,带来了新的语言特性:《 泛型》。它实现了类型的运行时多态,是一种 强大的语言特性。
今天要说的主题正是基于 LayerSupertype ,并结合了泛型技术而实现的,同样,它还有
一个重要的约定: 泛型的类型参数必须是最终的子类 。看如下一个例子:
1
public abstract class EntityBaseT
01
where T : En tityBaseT
02
{
03
public int Id { get; set; }
04 //sth else important
05
}
06
public class User : EntityBaseUser
07
{
08
public string Name { get; set; }
09
}
10
public class Article : EntityBaseArticle
11
{
12
public string Title { get; set; }
13}
En tityBase 作为所有实体类的基类,提供了统一的实体模板、约定和一些通用的基础实现。 基于这个基类的代码重用,使得子类的代码非常简单。这里和普通继承、普通泛型的不同点 在于父类在运行时绑定了具体子类的类型。
设计原理
为什么要这样设计?基类为什么不直接使用非泛型的基类呢?这是为了在基类实现的通用 方法中,能够以强类型的方式直接访问最终的子类。用上面的类举个例子,如果你使用
ActiveRecord 模式”那么要是使用非泛型的基类,你可能会在EntityBase 中加入方法:
但是,使用泛型基类绑定具体的子类后,我们会这样写代码:
1 User user = User.GetByld(id);
也就是说,这是一种更加类型安全的 API,用起来会很方便。
再举一个例子:由于泛型基类运行时绑定了不同的子类, 使得它本身的静态字段绑定到最终
的子类中的。例如上文中的例子, EntityBaseArticle 禾口 EntityBaseUser 其实是
不同的两个运行时类型。 这样,当我在EntityBaseT 内声明的静态字段是绑定到各子类
中的。如:我在 En tityBaseT 中声明了静态字段:
public abstract class En tityBaseT
{
private static reado nly stri ng TypeName = typeof(T).Name;
}
那么这个字段并不是为所有子类共享, 而是User.TypeName 和Article.TypeName 的值
不同,分别是User”和“Article。‘同样的功能,如果你要使用非泛型的基类,由于所有类
型共享一个运行时基类, 你需要考虑为在基类中为每个具体的类型存储对应的值, 例如,使
用一个字典存储:
1
public abstract class EntityBase
2
{
3
private static read only Dicti on aryType, string〉_allTypeNames = new
Dicti on aryType, stri ng();
4
public static string TypeName(Type concreteType)
5
{
6
return _allTypeNames[concreteType];
7
}
8
}
这样的API用起来,是不是很不易用呢?
上面只是举了些最简单的例子, 实际上,由于使用了绑定具体子类的泛型基类, 还会有很多
地方的设计变得更简单了,在此不再一一列举。
带来的问题
使用这种模式,缺点是显而易见的:
不能直接使用基类进行统一的处理
继续上面的例子,这样的设计,使得我们不能对所有的实体进行统一的处理。由于 User和
Article的基类其实是两个不同的运行时类型, 所以我不能把它们转换为同一个 实体”类型。
如:
EntityBase a = new Article。;
a = new User();
我甚至都不可能用到抽象的 En t
文档评论(0)