zoukankan      html  css  js  c++  java
  • 重构手法之在对象之间搬移特性【4】

    返回总目录

    本小节目录

    7Introduce Foreign Method(引入外加函数)

    概要

    你需要为提供服务的类增加一个函数,但你无法修改这个类。

    在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。

    动机

    好吧,我得不得说这个在C#中称为:扩展函数。这个其实也没什么好说的,这种事情发生过太多次了。假说你正在使用string类,它基本上提供了我们所需要的功能。但是,你正在做一项新服务,string类中恰巧无法提供。这时候你是不是想修改string的源代码,将这个功能加上。很可惜我们不能这么做,但是C#允许我们新建扩展函数。

    范例

    假如说,我们程序大量使用Dictionary<string,string>,我们要获得某个字典的value,可以这样做:

    var dictionary = new Dictionary<string, string>();
    string result;
    dictionary.TryGetValue("key", out result);

    但是我们每次都得定义一个out参数,这样很不方便。于是乎,我们建立一个扩展函数,至于怎么新建扩展函数,请自行百度。

    public static class DictionaryExt
    {
        public static string TryGetValue(this Dictionary<string, string> thisObj, string key)
        {
            if (thisObj == null || !thisObj.ContainsKey(key))
                return null;
            return thisObj[key] ?? "";
        }
    }

    这样一来,我们在使用的时候,就可以这样:

    var dictionary = new Dictionary<string, string>();
    var res = dictionary.TryGetValue("key");

    这样一来大大提高了我们的效率。

    小结

    如果客户类只是用这项功能一次,那么额外编码工作没什么大不了,甚至可能根本不需要原本提供服务的那个类。然而,如果你需要多次使用这个函数,就得不断重复这些代码。

    重复代码是软件万恶之源,重复代码应该被抽出来放进同一个函数中。

    8Introduce Local Extension(引入本地扩展)

    概要

    你需要为提供服务的类提供一些额外函数,但你无法修改这个类。

    建立一个新类,使它包含这些额外函数。让这个扩展品成为源类的子类。

    动机

    类的作者无法预知未来,他们常常没能为你预先准备一些有用的函数。如果只需要一两个函数,可以使用Introduce Foreign Method。但是如果需要的额外函数超过两个,外加函数就很难控制它们了。所以将这些函数组织在一起,让其成为源类的子类。这个子类称为本地扩展。

    范例

    我们还是以Dictionary<string,string>这个为例。

    首先新建一个DictionaryString,让其成为Dictionary<string,string>的子类。

    class DictionaryString : Dictionary<string, string>
    {
    
    }

    然后在扩展类中添加新特性,并使用Move Method将所有外加函数搬移到扩展类。

    class DictionaryString : Dictionary<string, string>
    {
        public string TryGetValue(Dictionary<string, string> thisObj, string key)
        {
            if (thisObj == null || !thisObj.ContainsKey(key))
                return null;
            return thisObj[key] ?? "";
        }
        //other methods...
    }

    使用方法和上个手法一样:

    DictionaryString dic=new DictionaryString();
    dic.TryGetValue("key");

    小结

    使用本地扩展让我们坚持了“函数和数据应该被统一封装”的原则。如果一直把本该放在扩展类中的代码零散地放置于其他类中,最终只会让其他这些类变得过分复杂,并使得其中函数难以被复用。

    阶段性小结

    在对象的设计过程中,“决定把责任放在哪儿”即使不是最重要的事,也是最重要的事之一。我们可能一开始并不能保证自己做对。但是我们可以使用Move FieldMove Method简单地移动对象行为,就可以解决这些问题。

    类往往会因为承担过多责任而变得臃肿不堪。这时候可以使用Extract Class将一部分责任分离出去。如果一个类变得太“不负责任”,就使用Inline Class将它融入另一个类。如果一个类使用了另一个类,运用Hide Delegate将这种关系隐藏起来。有时候隐藏委托类会导致拥有者的接口经常变化,此时需要使用Remove Middle Man

    当不能访问某个类的源码,又想把责任移进这个不可修改的类时,要使用Introduce Foreign MethodIntroduce Local Extension。如果加入的是一或两个函数,就会使用Introduce Foreign Method;如果不止一两个函数,就要使用Introduce Local Extension

    To Be Continued……

  • 相关阅读:
    Linux_磁盘管理
    Linux_安装软件包
    Linux_文件打包,压缩,解压
    Linux_系统管理命令(工作中经常使用到的)
    The method queryForMap(String, Object...) from the type JdbcTemplate refers to the missing type DataAccessException
    org.springframework.beans.factory.BeanDefinitionStoreException错误
    Java中动态代理工作流程
    Spring之<context:property-placeholder location="classpath:... "/>标签路径问题
    数据库连接问题之:Caused by: java.sql.SQLException: Connections could not be acquired from the underlying database!
    java环境变量的配置
  • 原文地址:https://www.cnblogs.com/liuyoung/p/7862381.html
Copyright © 2011-2022 走看看