可以这么说,不懂设计模式,难以理解面向对象的思想。也可以反过来说,不理解面向对象的思想,很难理解设计模式。不是吗?
今天我要和大家说一说c#实现模板模式,这是一个非常常用,并且简单的模式,在众多的设计模式中,这是我用的最多,而且是自然而然地应用,没有担心过什么。
曾几何时,模板模式悄悄地跑到我的代码里面了,也许是我看别人的代码时,不小心学到的。
有这么一个场景:我需要做“个人成果导出”和“管理后台的成果导出”,两个模块的实现的功能是一样的,都是在页面上展示成果列表,然后可以管理、查询、导出成果。至于具体如何展示,展示哪些数据,也就是具体的操作当然不一样了。也有一部分代码是相同的,比如说我要删除一条成果,是不是实现一致呢?只要你给一个id,我操作数据库,便删除了。难道这样的代码,我还需要拷贝两份?有人说,你为什么要弄两份呢,你写一个公共的方法,到时候调用即可。这貌似不错的解决办法。不过此解决方法遇到这种情况,怎么办呢?一个方法A的大部分代码都相同,就是有一些地方不同,这时候,我们还能提出来,作为公共的方法调用吗?有人说,你傻呀,你把大部分相同的代码提出来,作为公共的地方调用。那这样做,这个A方法,不是还是拷贝了两份?
这种情况下,我的模板方法该是时候出场了,且看代码:
解释下代码,我首先定义了一个抽象的控制器,由于首页的显示,不管是后台的,还是个人导出的,它们都是如此做法:
1、判断viewmodel是否为空
2、绑定页面下拉列表
3、填充viewmodel
4、返回视图
其中2和3两步,后台和个人导出的实现是不同的。后台的下拉列表更丰富些,viewmodel展示的字段也多点。所以,我们把2和3抽象出来,作为抽象方法。到具体运行时,决定到底调用后台导出的,还是个人导出的方法实现。因为,在编译阶段,我们也没法确定它到底调用哪个方法,因为它是抽象的。
且看管理后台的成果导出实现代码:
下面是个人成果导出的代码实现:
看代码,两个类名都起得一样,不好意思了,这两个类不在一个命名空间下。不过这样会给人造成阅读上的误会。那么有人会说,你上面的代码不是重复的吗?我说,不能看表面的,我是尽最大可能复用。不信,你看下面的代码:
管理后台的成果导出下拉列表绑定:
public override void BindSelect(ExportViewModel viewModel)
{
//学科类型绑定
ViewData["subjectTypes"] = SelectHelp.BindSelect<SubjectType>("学科系统");
//机构排名
ViewData["OrganizationOrders"] = new List<SelectListItem>()
{
new SelectListItem { Text = "本机构排名", Value = "-1"},
new SelectListItem { Text = "1", Value = "1"},
new SelectListItem { Text = ">1", Value = "2"},
new SelectListItem { Text = "2", Value = "3"},
new SelectListItem { Text = "<=2", Value = "4"},
new SelectListItem { Text = ">2", Value = "5"}
};
}
个人成果导出的下拉列表绑定:
public override void BindSelect(ExportViewModel viewModel)
{
//审核状态
ViewData["ReviewStates"] = new List<SelectListItem>()
{
new SelectListItem { Text = "审核状态", Value = "-1"},
new SelectListItem { Text = "待审核", Value = "1" },
new SelectListItem { Text = "审核通过", Value = "2"},
new SelectListItem { Text = "审核未通过", Value = "3"},
//new SelectListItem { Text = "自动审核中", Value = "4"},
new SelectListItem { Text = "撤回", Value = "5"},
new SelectListItem { Text = "禁止", Value = "6"}
};
//署名情况
ViewData["Bylines"] = new List<SelectListItem>()
{
new SelectListItem { Text = "署名情况", Value = "-1"},
new SelectListItem { Text = "第一作者", Value = "1" },
new SelectListItem { Text = "通信作者", Value = "2"},
new SelectListItem { Text = "通信作者或者第一作者", Value = "3"}
//new SelectListItem { Text = "非第一和通信作者", Value = "4"}
};
//排序
ViewData["Orders"] = new List<SelectListItem>()
{
new SelectListItem { Text = "提交日期", Value = "1"},
new SelectListItem { Text = "年度", Value = "0"}
};
}
模板模式,体现了代码复用的思想,也体现了面向对象中的多态。有人说,你定义的抽象方法,子类要实现,这些不都重复吗?我说的是,模板方法还有一个特点,就是我们的代码主干逻辑非常清晰,易于阅读,也好修改。如果说一味地提取公共方法,然后调用,最后也不好改,公共方法作为”公共服务“”,万一不能满足个别”客户端“,也就是调用端的需求,我们怎么办呢?此时,抽象类的继承机制,可以解决问题。
当然不能说公共类作为公共服务就不好,就看什么场合了。比如说,咱们经常用的工具类,处理字符串的,日期的,数据库操作的。这些工具类是非常有帮助的,也非常好的体现了代码复用原则。好了,模板模式就介绍到这里。