• 必会重构技巧(二):使用多态替换条件


    使用多态替换条件:指在进行类型检查和执行某些类型操作时,最好将算法封装在类中,并且使用多态来对代码中的调用进行抽象

      举例理解:看定义可能比较迷糊,其实说的简单一点,对于使用分支语句并且分支条件是和类型检查相关的程序段,如 if(type == typeof(TypeA)){...}else if(type == typeof(TypeB)){...},可以把{...}中的Code,尝试放到if的条件中去。然后通过检查Type就可以直接返回需要的东东了,这样做可以利用已有的继承层次进行计算,比较便于维护。如果还是觉得说的太抽象,可以看看下面的代码感觉一下。

      项目实例:用WPF做一个网游的客户端Demo,里面需要对商品,邮件,物品栏做分页操作。于是手动写了几个分页的类。开始是把分页的计算方法都写在了事件里面的,每一个Button绑定一个事件,每次需要修改或者使用分页的时候,都要找到相关类进行修改,复制,各个方法的耦合程度大增,程序可读性,复用性和可维护性都不太好。虽然这个项目是很久之前做的了,但这里既然想起来了,觉得还是可以尝试用这种重构方法,效果如何大家自己看看吧。
      先来看看原始的未经过重构的代码:

    原始代码

    //x:目标页数索引值 y:每页显示记录个数 这里不Care你是如何取到这几个值的和对这两个Int值合法性的验证
    protected void btnFirstPage_Click(object sender, EventArgs e)
    {
      Button btn = sender as Button;
      if (btn != null)
      {
        repDataList.DataSource = Getdata(x,y); //Get Date from DB
      }
    }
    protected void btnPrePage_Click(object sender, EventArgs e)
    {
      Button btn = sender as Button;
      if (btn != null)
      {
        repDataList.DataSource = Getdata(x, y); //Get Date from DB
      }
    }
    protected void btnNextPage_Click(object sender, EventArgs e)
    {
      Button btn = sender as Button;
      if (btn != null)
      {
        repDataList.DataSource = Getdata(x, y); //Get Date from DB
      }
    }
    protected void btnlastPage_Click(object sender, EventArgs e)
    {
      Button btn = sender as Button;
      if (btn != null)
      {
        repDataList.DataSource = Getdata(x, y); //Get Date from DB
      }
    }
    private DataSet Getdata(int targetPageIndex, int numberPerPage) //Get Date from DB
    {
      throw new NotImplementedException(); //Here some code to retrive Data from DB
    }

      上面的几段代码可以实现功能,但是却存在以下几点问题。
        (1)如果有多个页面需要使用分页,同样的代码需要复制多次,复用性差
        (2)第一个问题造成了第二个问题,如果需要修改某段方法,那所有的相关页面都要修改,可维护性差
        (3)相似逻辑的方法写在了多个事件中,可读性差
      为了解决这三个问题,现在重构后的代码如下:

    重构后

    public abstract class Paging
    {
      public int TargetPageIndex { get; set; }
      public int NumberPerPage { get; set; }
      public abstract DataSet DataList { get; }
    }
    public class FirstPage : Paging
    {
      public FirstPage(int targetPageIndex, int numberPerPage)
      {
        TargetPageIndex = targetPageIndex;
        NumberPerPage = numberPerPage;
      }
      public override DataSet DataList
      {
        get
        {
          return Getdata(TargetPageIndex, NumberPerPage);
        }
      }
    }
    public class PrePage : Paging
    {
      public PrePage(int targetPageIndex, int numberPerPage)
      {
        TargetPageIndex = targetPageIndex;
        NumberPerPage = numberPerPage;
      }
      public override DataSet DataList
      {
        get
        {
          return Getdata(TargetPageIndex, NumberPerPage);
        }
      }
    }
    public class NextPage : Paging
    {
      public NextPage(int targetPageIndex, int numberPerPage)
      {
        TargetPageIndex = targetPageIndex;
        NumberPerPage = numberPerPage;
      }
      public override DataSet DataList
      {
        get
        {
          return Getdata(TargetPageIndex, NumberPerPage);
        }
      }
    }
    public class LastPage : Paging
    {
      public LastPage(int targetPageIndex, int numberPerPage)
      {
        TargetPageIndex = targetPageIndex;
        NumberPerPage = numberPerPage;
      }
      public override DataSet DataList
      {
        get
        {
          return Getdata(TargetPageIndex, NumberPerPage);
        }
      }
    }

    以上代码可以独立出一个Paging的类,略加修改就可以对应任意的DataSource。

    前台调用代码

    protected void btnPaging_Click(object sender, EventArgs e)
    {
      Button btn = sender as Button;
      if (btn == null) return;
      Paging page;
      switch (btn.CommandArgument)
      {
        case "FirstPage":
          page = new FirstPage(x,y);
          repDataList.DataSource = page.DataList;
          break;
        case "PrePage":
          page = new PrePage(x, y);
          repDataList.DataSource = page.DataList;
          break;
        case "NextPage":
          page = new NextPage(x, y);
          repDataList.DataSource = page.DataList;
          break;
        case "LastPage":
          page = new LastPage(x, y);
          repDataList.DataSource = page.DataList;
          break;

      }
    }

    个人感觉,对于本例中的应用,好处并不是很明显,也许是我写的有问题,也许是我选择例子有问题。尽管如此,重构的思想体现出来了,那就是把算法封装到多态中。此种重构在对于含类型判断条件的复杂算法分支的应用上,效果还是比较显著的。
  • 相关阅读:
    yaml 文件解析
    python 实现自动部署测试环境
    运行ride.py报错,闪退
    selenium 配置ie11 浏览器
    自动化测试(1)selenium+python+chrome 连接测试
    scrapy爬虫框架
    drf内置排序源码
    celery基本使用
    C# 如何复制(拷贝)Label控件上的文本【新方法】
    C# 使用PictureBox实现图片按钮控件
  • 原文地址:https://www.cnblogs.com/ywsoftware/p/2892655.html
Copyright © 2020-2023  润新知