人言:总结使人进步;为了进一步巩固自己学到的东西和了解新的知识,决定通过博客园来记录自己学习设计模式的过程,本人没有学过设计模式,只是背过一些概念,从现在起,我会通过一个个的例子来让自己学习每个模式并记录下来,有需要的朋友一起来。
“面向对象”这个字眼,估计你已经熟的透了,然而可能还是无法在实际编程中运用自如,尽管我们都知道“类”、“封装、继承、多态”概念,却依然写着面向过程的代码。举个最简单的例子:分页控件
1 public partial class WebForm1 : System.Web.UI.Page
2 {
3 protected void Page_Load(object sender, EventArgs e)
4 {
5
6 }
7
8 protected string BuildPager(int pageIndex, int count, int pageSize = 10)
9 {
10 StringBuilder strB = new StringBuilder();
11 int pageCount = count / pageSize + (count % pageSize == 0 ? 0 : 1);
12
13 for (int i = 0; i < pageCount; i++)
14 {
15 strB.AppendFormat("<a href='/webform1.aspx?pindex={0}' >{1}</a>", i, i + 1);
16 }
17
18 return strB.ToString();
19 }
20 }
WebForm前台调用:
<div> <%=BuildPager(1,100,10) %> </div>
打印的样子:
我们主要关注BuildPager方法,对于以上的代码能实现功能吗?绝对可以,面向对象吗?也算是有一点点,这时可能就会有人问,怎么就算面向对象了,或许你立刻想到三要素“封装继承多态”了,之前听到一位大牛对面向对象的总结:对象的职责问题。个人感觉总结的精辟到了极点。
我们不得不考虑关于BuildPager方法的几个使用情形,来来考量它是否符合。
第一:它是否便于其他类或对象调用;比如还有一个页面B需要分页,B是否能很容易调用这个方法呢?显然能:在B中写:WebForm1 wf = new WebForm1(); wf.BuilderPager(....);就可以了。但是基于刚才提到的“对象的职责问题”再考虑一下,就会发现,“BuildPager"功能并不应该属于WebFomr1这个类,因为WebForm2可能也会有,这是可能有人会想,那就放到基类Page里去,这样所有的子类都有了,好想法,然后忽略了一种不同页面,分页标签不一样的情况(有的用A有的用span),这是可能你会想到那就用Virtual,不同的分页方法就在子类里重写,好办法。这时我们已经运用了继承和多态两个特性。但是还有一种情况,子类的5个页面的分页用A标签,另外10个页面用span标签,这时,我们当然可以通过重写实现。但是会出现大量的重复代码。怎么办呢,运用封装的概念,再新建一个类Pager,把分页的代码放进去。
1 public class Pager
2 {
3 public virtual string BuildPager(int pageIndex, int count, int pageSize = 10)
4 {
5 StringBuilder strB = new StringBuilder();
6 int pageCount = count / pageSize + (count % pageSize == 0 ? 0 : 1);
7
8 for (int i = 0; i < pageCount; i++)
9 {
10 strB.AppendFormat("<a href='/webform1.aspx?pindex={0}' >{1}</a>", i, i + 1);
11 }
12
13 return strB.ToString();
14 }
15 }
对于运用不同标签的方式,我们通过集成和多态来实现。
调用的时候,需要那种方式,就创建那种对象。
1 protected void Page_Load(object sender, EventArgs e)
2 {
3 Pager pager = new PagerUseSpanTag(); // 或者 new PagerUseATag();
4
5 var pagerHtml = pager.BuildPager(0, 1000, 10);
6 }
这一的话,对于刚才的那个多个页面有相同分页的需求就轻而易举的解决了,现在能很容易的扩展分页的功能了,然而还有一个问题不知你发现了没,就是我们的分页方法的代码,它把分页的逻辑和展现都写到一个函数里了。如果有一天,Leader说分页的逻辑要变,那么你需要重写所有的Pager子类的分页方法了,而且修改的内容多数相同(只修改逻辑)。根据”对象的职责问题“,我们发现,分页的逻辑和分页的展示 对Pager类而言应该是两个独立的功能,Pager类应该这样写:
1 public class Pager
2 {
3 //逻辑
4 public virtual string BuildPager(int pageIndex, int count, int pageSize = 10)
5 {
6 StringBuilder strB = new StringBuilder();
7 int pageCount = count / pageSize + (count % pageSize == 0 ? 0 : 1);
8
9 for (int i = 0; i < pageCount; i++)
10 {
11 strB.AppendFormat(GetUnitPageHtml(i, (i + 1).ToString()));
12 }
13
14 return strB.ToString();
15 }
16
17 //展示
18 protected virtual string GetUnitPageHtml(int pageIndex, string pageText)
19 {
20 return string.Format("<a href='/webform1.aspx?pindex={0}' >{1}</a>", pageIndex, pageText);
21 }
22 }
这样的话,如果逻辑变了,在子类中重写”BuildPager“方法,如果展示变了”GetUnitPageHtml"方法,再看他两个子类写法:
如果 分页标签为A的逻辑变了,那就新加类 BigPagerUseATag,并重写 BuildPager方法即可。
1 public class BigPagerUseATag : PagerUseATag
2 {
3 public override string BuildPager(int pageIndex, int count, int pageSize = 10)
4 {
5 StringBuilder strB = new StringBuilder();
6
7 /*
8 * 你的新的分页逻辑
9 */
10
11 return strB.ToString();
12 }
13 }
到目前为止,这个分页基本上能解决大部分的分页遇到的问题了,无论扩展性还是修改时的成本控制,都得到了有效的提升。在这个过程中,我们运用面向对象的理念,封装:把正确的功能放到正确的类中(如果没有类就新建),继承:修改功能尽量不要直接修改代码,通过新增子类的方式实现,多态:不同的功能在不同的子类中有不一样的效果。到此Pager可以称为一个可复用的组件了,可以单独放到某个框架中供多个项目调用了。
设计模式的基础是面向对象,面向对象的基础夯实了,设计模式就是思考解决问题的捷径思路。
谢谢!