Fork me on GitHub

重构手法之在对象之间搬移特性【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……

 

posted @ 2017-11-25 09:49  NaYoung  阅读(593)  评论(0编辑  收藏  举报