zoukankan      html  css  js  c++  java
  • 设计模式之初:理解面向对象设计

         人言:总结使人进步;为了进一步巩固自己学到的东西和了解新的知识,决定通过博客园来记录自己学习设计模式的过程,本人没有学过设计模式,只是背过一些概念,从现在起,我会通过一个个的例子来让自己学习每个模式并记录下来,有需要的朋友一起来。

       “面向对象”这个字眼,估计你已经熟的透了,然而可能还是无法在实际编程中运用自如,尽管我们都知道“类”、“封装、继承、多态”概念,却依然写着面向过程的代码。举个最简单的例子:分页控件

     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     }

    对于运用不同标签的方式,我们通过集成和多态来实现。

    A标签分页类和Span标签分页类

    调用的时候,需要那种方式,就创建那种对象。

    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可以称为一个可复用的组件了,可以单独放到某个框架中供多个项目调用了。

    设计模式的基础是面向对象,面向对象的基础夯实了,设计模式就是思考解决问题的捷径思路。 

    谢谢!

  • 相关阅读:
    吴裕雄--天生自然PHP-MySQL-JavaScript学习笔记:Cookies、会话和身份验证
    吴裕雄--天生自然PHP-MySQL-JavaScript学习笔记:表单处理
    吴裕雄--天生自然PHP-MySQL-JavaScript学习笔记:使用PHP访问MySQL
    吴裕雄--天生自然PHP-MySQL-JavaScript学习笔记:掌握MySQL
    吴裕雄--天生自然PHP-MySQL-JavaScript学习笔记:MySQL入门
    吴裕雄--天生自然PHP-MySQL-JavaScript学习笔记:实用PHP技术
    吴裕雄--天生自然PHP-MySQL-JavaScript学习笔记:PHP数组
    吴裕雄--天生自然PHP-MySQL-JavaScript学习笔记:PHP函数与对象
    (008)spring之BeanPostProcessor的执行时机及作用
    (007)spring容器获取ApplicationContext
  • 原文地址:https://www.cnblogs.com/wimlh/p/4011043.html
Copyright © 2011-2022 走看看