模块高度耦合 该这样化解之 -《代码不朽》-架构师书房

大家好,我是码农老吴,欢迎收看极客架构师推出的架构师书房栏目。今天,我继续给大家解读《代码不朽》这本书。

上期,我们分享了,拆分过大类的方法,根据不同关注点拆分类(Split Classes to Separate Concerns),本期,我们看另外一个策略,隐藏接口背后的特定实现(Hide Specialized Implementations Behind Interfaces),目的是达到模块之间的解耦和。


模块高度耦合 该这样化解之 -《代码不朽》-架构师书房


案例简介

这个案例代码,说的是一个移动app项目,里面的DigitalCamera类,用于提供相机的相关操作,比如拍照,打开闪光灯,关闭闪光灯等功能。另外一个类SmartphoneApp,是DigitalCamera类的调用方,或者叫客户方,依赖DigitalCamera类。我们看看在项目发展中,出现的问题。

第一版

DigitalCamera类

package eu.sig.training.ch06.digitalcamera;

import java.awt.Image;
import java.awt.image.BufferedImage;

// tag::DigitalCamera[]
public class DigitalCamera {
    public Image takeSnapshot() {
        // ...
        // end::DigitalCamera[]
        return new BufferedImage(1920, 1080, BufferedImage.TYPE_INT_ARGB);
        // tag::DigitalCamera[]
    }

    public void flashLightOn() {
        // ... 
    }

    public void flaslLightOff() {
        // ... 
    }
}
// end::DigitalCamera[]

SmartphoneApp 类

注意,这个类中,建立了DigitalCamera类的对象,所以它依赖DigitalCamera类。

package eu.sig.training.ch06.digitalcamera;

import java.awt.Image;

@SuppressWarnings("unused")
// tag::SmartphoneApp[]
public class SmartphoneApp {
    private static DigitalCamera camera = new DigitalCamera();

    public static void main(String[] args) {
        // ...        
        Image image = camera.takeSnapshot();
        // ...
    }
}
// end::SmartphoneApp[]

第二次升级

DigitalCamera类

第二次升级,这个类,增加了不少功能,如录制视频,设置定时器,放大缩小等功能。

package eu.sig.training.ch06.advanceddigitalcamera;

import java.awt.Image;
import java.awt.image.BufferedImage;

@SuppressWarnings("unused")
// tag::DigitalCamera[]
public class DigitalCamera {
    public Image takeSnapshot() {
        // ...
        // end::DigitalCamera[]
        return new BufferedImage(1920, 1080, BufferedImage.TYPE_INT_ARGB);
        // tag::DigitalCamera[]
    }

    public void flashLightOn() {
        // ... 
    }

    public void flaslLightOff() {
        // ... 
    }

    public Image takePanoramaSnapshot() {
        // end::DigitalCamera[]
        return new BufferedImage(1920, 1080, BufferedImage.TYPE_INT_ARGB);
        // tag::DigitalCamera[]
        // ... 
    }

    public Video record() {
        // ...
        // end::DigitalCamera[]
        return new Video();
        // tag::DigitalCamera[]
    }

    public void setTimer(int seconds) {
        // ... 
    }

    public void zoomIn() {
        // ...
    }

    public void zoomOut() {
        // ... 
    }
}
// end::DigitalCamera[]

升级带来的潜在风险

当我们升级了DigitalCamera类的功能之后,对它有直接依赖的SmartphoneApp类,也相应的获得了,访问这些新功能的权限。这可能不是我们所期望的,SmartphoneApp类可能在DigitalCamera类不知情的情况下,使用了新增的功能。如何解决这个问题,就需要使用我们今天分享的技巧,隐藏接口背后的特定实现(Hide Specialized Implementations Behind Interfaces)。

如何理解这句话呢,其实,换种说法,它就是我们平时所说的,面向接口编程。通过接口,来约定双方的职责与权利。具体如何落地,看看作者的做法。

重构后

类图-典型的静态工厂模式

模块高度耦合 该这样化解之 -《代码不朽》-架构师书房

接口及类

SimpleDigitalCamera:抽象产品

DigitalCamera:具体产品

SDK:简单工厂模式

SmartphoneApp:工厂客户方

SimpleDigitalCamera:抽象产品

package eu.sig.training.ch06.simpledigitalcamera;

import java.awt.Image;

// tag::SimpleDigitalCamera[]
public interface SimpleDigitalCamera {
    Image takeSnapshot();

    void flashLightOn();

    void flashLightOff();
}
// end::SimpleDigitalCamera[]

DigitalCamera:具体产品

package eu.sig.training.ch06.simpledigitalcamera;

import java.awt.Image;

// tag::DigitalCamera[]
public class DigitalCamera implements SimpleDigitalCamera {
    // ...
    // end::DigitalCamera[]
    public Image takeSnapshot() {
        return null;
    }

    public void flashLightOn() {}

    public void flashLightOff() {}
    // tag::DigitalCamera[]
}
// end::DigitalCamera[]

SDK:简单工厂模式

package eu.sig.training.ch06.simpledigitalcamera;

public class SDK {

    public static SimpleDigitalCamera getCamera() {
        return new DigitalCamera();
    }

}

SmartphoneApp:工厂客户方

package eu.sig.training.ch06.simpledigitalcamera;

import java.awt.Image;

@SuppressWarnings("unused")
// tag::SmartphoneApp[]
public class SmartphoneApp {
    private static SimpleDigitalCamera camera = SDK.getCamera();

    public static void main(String[] args) {
        // ...
        Image image = camera.takeSnapshot();
        // ...
    }
}
// end::SmartphoneApp[]

点评

上面的解决方法,就是一个典型的简单工厂模式的应用。这样,SmartphoneApp类,依赖的就仅仅是个接口SimpleDigitalCamera接口,而不是实现类,所以只能访问接口中公开的方法。有关简单工厂模式,我在《架构师基本功之设计模式》中,已经分享过,不了解的朋友可以参考一下。

本期内容我们就分享到这里,下期,我们分享第7章的内容,架构组件的松耦合(Couple Architecture Components Loosely)。

极客架构师,专注架构师成长,我们下期见。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章