人言:总结使人进步;为了进一步巩固自己学到的东西和了解新的知识,决定通过博客园来记录自己学习设计模式的过程,本人没有学过设计模式,只是背过一些概念,从现在起,我会通过一个个的例子来让自己学习每个模式并记录下来,有需要的朋友一起来。
“面向对象”这个字眼,估计你已经熟的透了,然而可能还是无法在实际编程中运用自如,尽管我们都知道“类”、“封装、继承、多态”概念,却依然写着面向过程的代码。举个最简单的例子:分页控件
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("{1}", i, i + 1); 16 } 17 18 return strB.ToString(); 19 } 20 }
WebForm前台调用:
<%=BuildPager(1,100,10) %>
打印的样子:
我们主要关注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("{1}", 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("{1}", 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可以称为一个可复用的组件了,可以单独放到某个框架中供多个项目调用了。
设计模式的基础是面向对象,面向对象的基础夯实了,设计模式就是思考解决问题的捷径思路。
谢谢!