小酌重构系列[13]——移除中间类

我们有时候在应用程序中可能编写了一些“幽灵”类,“幽灵”类也叫中间类。这些中间类可能什么事儿都没做,而只是简单地调用了其他的组件。这些中间类没有发挥实际的作用,它们增加了应用程序的层级(layer),并且增加了应用程序的复杂性。这时,我们应将这样的中间类删除,甚至删除中间类所处的“中间层”——这就是本文要讲的重构策略“移除中间类”。

移除中间类

图说

这个重构策略比较容易理解,下面这幅图演示了它的重构过程。

例外

通常情况下,无效的中间类可能是因为滥用设计模式而造成的。

如果设计模式使用的恰当,这个重构策略就不适用了,比如用“门面模式”、“适配器模式”和“代理模式”的场景。

下面我以“门面模式”简单说明一下不适用的场景。

门面模式

门面模式,是指提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口。使得子系统更容易使用。

通过区分“门面模式”的使用场景,可以判断是否应该使用“移除中间类”:

1、客户只需要使用某个复杂系统的子集,或者需要以一种特殊的方式与系统交互时,使用门面模式。

2、当需要跟踪原系统的使用情况时 ,使用门面模面模式。因为所有对系统的访问都经过FACADE,所以可以很容易地监视系统的使用 。

3、 希望封装和隐藏原系统时。

4、编写新类的成本小于所有人使用和维护原系统使用所需的成本时

示例

重构前

这段代码定义了3个类,Consumer依赖于AccountManager,AccountManager依赖于AccountDataProvider。

隐藏代码

public class Consumer
{
    public AccountManager AccountManager { get; set; }

    public Consumer(AccountManager accountManager)
    {
        AccountManager = accountManager;
    }

    public void Get(int id)
    {
        Account account = AccountManager.GetAccount(id);
    }
}

public class AccountManager
{
    public AccountDataProvider DataProvider { get; set; }

    public AccountManager(AccountDataProvider dataProvider)
    {
        DataProvider = dataProvider;
    }

    public Account GetAccount(int id)
    {
        return DataProvider.GetAccount(id);
    }
}

public class AccountDataProvider
{
    public Account GetAccount(int id)
    {
        // get account
    }
}

AccountManager类作为中间类,没有起到任何实际的作用,它只是依葫芦画瓢地套用了AccountDataProvider做的事情。

重构后

移除中间类后,Consumer类直接依赖于AccountDataProvider类。

隐藏代码

public class Consumer
{
    public AccountDataProvider AccountDataProvider { get; set; }

    public Consumer(AccountDataProvider dataProvider)
    {
        AccountDataProvider = dataProvider;
    }

    public void Get(int id)
    {
        Account account = AccountDataProvider.GetAccount(id);
    }
}

public class AccountDataProvider
{
    public Account GetAccount(int id)
    {
        // get account
    }
}

【关注】keepfool

时间: 2024-10-13 19:35:35

小酌重构系列[13]——移除中间类的相关文章

小酌重构系列[11]——提取基类、提取子类、合并子类

概述 继承是面向对象中的一个概念,在小酌重构系列[7]--使用委派代替继承这篇文章中,我"父子关系"描述了继承,这是一种比较片面的说法.后来我又在UML类图的6大关系,描述了继承是一种"is a kind of"关系,它更偏向于概念层次,这种解释更契合继承的本质.本篇要讲的3个重构策略提取基类.提取子类.合并子类都是和继承相关的,如果大家对继承的理解已经足够深刻了,这3个策略用起来应该会得心应手. 提取基类 定义:如果有超过一个类有相似的功能,应该提取出一个基类,并

小酌重构系列[12]——去除上帝类

关于上帝类 神说:"要有光",就有了光.--<圣经>.上帝要是会写程序,他写的类一定是"上帝类".程序员不是上帝,不要妄想成为上帝,但程序员可以写出"上帝类".上帝是唯一的,上帝的光芒照耀人间,上帝是很爱面子的,他知道程序员写了"上帝类",抢了他的风头,于是他降下神罚要惩戒程序员.--既然你写了"上帝类",那么就将你流放到艰难地修改和痛苦的维护的炼狱中,在地狱之火中永久地熬炼. 你看,上帝也是有

小酌重构系列[21]&mdash;&mdash;避免双重否定

避免双重否定 在自然语言中,双重否定表示肯定.但是在程序中,双重否定会降低代码的可读性,使程序不易理解,容易产生错觉.人通常是用"正向思维"去理解一件事情的,使用双重否定的判断,需要开发者以"逆向思维"的方式去理解它的含义.另外,在写程序时,"!"符号很容易被疏忽和遗漏,一不小心则会编写出错误的代码,从而产生bug.所以,在程序中,我们应当尽量避免使用双重否定. 优惠券是否未被使用? 还是以在线商城给用户发放优惠券为例,由于优惠券的初始状态是未被

小酌重构系列[17]&mdash;&mdash;提取工厂类

概述 在程序中创建对象,并设置对象的属性,是我们长干的事儿.当创建对象需要大量的重复代码时,代码看起来就不那么优雅了.从类的职责角度出发,业务类既要实现一定的逻辑,还要负责对象的创建,业务类干的事儿也忒多了点.对象创建也是"一件事",我们可以将"这件事"从业务代码中提取出来,让专门的类去做"这件事",这个专门的类一般是"工厂类",这样使得业务类和工厂类各司其职,代码整洁性得以提高.这就是本文要讲的主题--提取工厂类. 工厂举例

小酌重构系列[15]&mdash;&mdash;策略模式代替分支

前言 在一些较为复杂的业务中,客户端需要依据条件,执行相应的行为或算法.在实现这些业务时,我们可能会使用较多的分支语句(switch case或if else语句).使用分支语句,意味着"变化"和"重复",每个分支条件都代表一个变化,每个分支逻辑都是相似行为或算法的重复.当追加新的条件时,我们需要追加分支语句,并追加相应的行为或算法. 上一篇文章"使用多态代替条件判断"中,我们讲到它可以处理这些"变化"和"重复&qu

小酌重构系列[20]&mdash;&mdash;用条件判断代替异常

概述 异常处理的关键在于何时处理异常以及如何使用异常,有些开发者会觉得try catch的处理和使用难以把握,于是他们秉承着"您可错杀一千,不可放过一个"的想法,给所有的方法添加try catch. 这种方式会对应用程序造成什么影响吗? 从用户角度出发,用户确实难以察觉到什么,应用程序运行正常,使用的体验好像也没什么差别. 从程序角度出发,大量的try catch会降低代码的可读性,只有在异常触发时才会对程序的性能造成较大的影响. 这两种角度有对错吗? 二者都没有错,第一种角度甚至要远

小酌重构系列[2]&mdash;&mdash;提取方法、提取方法对象

前言 "艺术源于生活"--代码也源于生活,你在生活中的一些行为习惯,可能会恰如其分地体现在代码中.当实现较为复杂的功能时,由于它包含一系列的逻辑,我们倾向于编写一个"大方法"来实现.为了使项目便于维护,以及增强代码的可读性,我们有必要对"大方法"的逻辑进行整理,并提取出分散的"小方法".这就是本文要讲的两种重构策略:提取方法.提取方法对象. 如何快速地找到想读的书? 在生活中,我是一个比较随意的人,平时也买了不少书去看.我的书

小酌重构系列[18]&mdash;&mdash;重命名

概述 代码是从命名开始的,我们给类.方法.变量和参数命名,我们也给解决方案.工程.目录命名.在编码时,除了应该遵守编程语言本身的命名规范外,我们应该提供好的命名.好的命名意味着良好的可读性,读你代码的人无需太多的注释,就能通过名称知道它是什么,它能做什么事儿,以及它应该怎么用. 我们命名.命名,不断地命名.既然有这么多命名要做,我们不妨做好他. 关于命名 取名字的成本 取个名字很简单,取个好的名字就不那么容易了.快速随意地取个名字,还不如花点时间取个好名字,因为好名字省下来的时间要比花掉的多.

小酌重构系列目录汇总

为了方便大家阅读这个系列的文章,我弄了个目录汇总. 方法.字段重构 移动方法 (2016-04-24) 提取方法.提取方法对象 (2016-04-26) 方法.字段的提升和降低 (2016-05-01) 分解方法 (2016-05-02) 为布尔方法命名 (2016-05-03) 引入对象参数 (2016-05-04) 类.接口重构 使用委派代替继承 (2016-05-07) 提取接口 (2016-05-08) 解除依赖 (2016-05-09) 分离职责 (2016-05-11) 提取基类.提