大话设计模式之外观模式

2018-08-15  本文已影响1人  大炮对着虫子

外观模式,为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这个子系统更加容易使用。

假如我们开车上班,为了使车子走起来我们要做些什么操作?假设我们开的是手动挡的车,我们需要按这个步骤来操作:

  1. 用遥控钥匙解锁车门

  2. 打开车门

  3. 关上车门

  4. 启动发动机

  5. 挂挡

  6. 松手刹

  7. 松离合器

  8. 车子开始走
    如果用java代码来描述这一系列的动作该怎样设计呢?很显然,我们需要几个类,而每个类都有自己的一些行为,我先用UML类图来描述一下这些类以及它们的行为。

image.png

汽车钥匙:

public class CarKeys {
    public void unlock() {
        System.out.println("Key unlock car.");
    }
    
    public void lock() {
        System.out.println("Key lock car.");
    }
}

车门:

public class CarDoors {
    public void open() {
        System.out.println("Open the car door.");
    }
    
    public void close() {
        System.out.println("Close the car door.");
    }
}

发动机

public class Engine {
    public void start() {
        System.out.println("Car Engine started.");
    }
    
    public void stop() {
        System.out.println("Car Engine stopped.");
    }
}

变速箱:

public class Gear {
    public void setGear(int gear) {
        System.out.println(String.format("Change to gear %s", gear));
    }
}

手刹:

public class ParkingBrake {
    public void release() {
        System.out.println("Release parking brake.");
    }
    
    public void hold() {
        System.out.println("Hold parking brake.");
    }
}

离合器:

public class Clutch {
    public void release() {
        System.out.println("Release clutch slowly.");
    }
    
    public void push() {
        System.out.println("Push clutch quickly");
    }
}

汽车:

public class Car {
    public void go() {
        System.out.println("Car go.");
    }
    
    public void stop() {
        System.out.println("Car Stop");
    }
}

客户端代码:

import org.junit.Before;
import org.junit.Test;

public class MyTest2 {
    private CarKeys carKeys;
    private CarDoors carDoors;
    private Engine engine;
    private Gear gear;
    private ParkingBrake parkingBrake;
    private Clutch clutch;
    private Car car;
    private DriveCarFacade facade;
    
    @Before
    public void setup() {
        carKeys = new CarKeys();
        carDoors = new CarDoors();
        engine = new Engine();
        gear = new Gear();
        parkingBrake = new ParkingBrake();
        clutch = new Clutch();
        car = new Car();
        facade = new DriveCarFacade();
        facade.setCarKeys(carKeys);
        facade.setCarDoors(carDoors);
        facade.setEngine(engine);
        facade.setGear(gear);
        facade.setParkingBrake(parkingBrake);
        facade.setClutch(clutch);
        facade.setCar(car);
    }
    
    @Test
    public void typicalWay4Go() {
        carKeys.unlock();
        carDoors.open();
        engine.start();
        gear.setGear(1);
        parkingBrake.release();
        clutch.release();
        car.go();
    }    
}

从以上UML类图及代码可以看到,我创建了7个类,每个类都有自己的行为,为了使车子走起来,我们有一个客户端类来驱动这7个类及它们的行为,但是从这种设计里面我们看到一些弊端:

  1. 车子的启动顺序由客户决定,但是万一客户弄错了呢?例如还没有按遥控钥匙就去开车门或是发动机还没有启动就挂挡。或者更糟糕的情况,客户根本就没有调用松离合器的方法。
  2. 现在7个组件跟客户都是聚合关系,如果这7个组件类里面有关于行为方法的改动(例如参数列表的变化)就势必要更改客户端的调用代码。

从以上两个缺点来看,我觉得这种设计是紧耦合并且是脆弱的。试想有一天,客户希望他的汽车能够自动驾驶,他不想要每天重复这么多繁琐的动作,他想要的就是按一下汽车钥匙的go按钮然后汽车把剩下的所有步骤都完成,他只要下车去办公室就好了。

那么如何解决这种问题?

为了解决这种问题,我们需要引入外观模式,也有的称之为门面模式。门面模式的定义是这样的:外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

外观模式也诠释了面向对象设计原则中的迪米特法则(最少知识原则),最少知识意指一个类应该只跟它需要打交道的类沟通,这样可以有效的保证松散耦合

image.png

外观类:

public class DriveCarFacade {
    private CarKeys carKeys;
    private CarDoors carDoors;
    private Engine engine;
    private Gear gear;
    private ParkingBrake parkingBrake;
    private Clutch clutch;
    private Car car;
    
    public void setCarKeys(CarKeys carKeys) {
        this.carKeys = carKeys;
    }
    public void setCarDoors(CarDoors carDoors) {
        this.carDoors = carDoors;
    }
    public void setEngine(Engine engine) {
        this.engine = engine;
    }
    public void setGear(Gear gear) {
        this.gear = gear;
    }
    public void setParkingBrake(ParkingBrake parkingBrake) {
        this.parkingBrake = parkingBrake;
    }
    public void setClutch(Clutch clutch) {
        this.clutch = clutch;
    }
    public void setCar(Car car) {
        this.car = car;
    }

    public void go() {
        this.carKeys.unlock();
        this.carDoors.open();
        this.engine.start();
        this.gear.setGear(1);
        this.parkingBrake.release();
        this.clutch.release();
        this.car.go();
    }
    
    public void stop() {
        this.clutch.push();
        this.gear.setGear(0);
        this.parkingBrake.hold();
        this.engine.stop();
        this.car.stop();
        this.carDoors.close();
        this.carKeys.lock();
    }
}

客户端代码:

import org.junit.Before;
import org.junit.Test;

public class MyTest {
    
    private CarKeys carKeys;
    private CarDoors carDoors;
    private Engine engine;
    private Gear gear;
    private ParkingBrake parkingBrake;
    private Clutch clutch;
    private Car car;
    private DriveCarFacade facade;
    
    @Before
    public void setup() {
        carKeys = new CarKeys();
        carDoors = new CarDoors();
        engine = new Engine();
        gear = new Gear();
        parkingBrake = new ParkingBrake();
        clutch = new Clutch();
        car = new Car();
        facade = new DriveCarFacade();
        facade.setCarKeys(carKeys);
        facade.setCarDoors(carDoors);
        facade.setEngine(engine);
        facade.setGear(gear);
        facade.setParkingBrake(parkingBrake);
        facade.setClutch(clutch);
        facade.setCar(car);
    }
    
    @Test
    public void typicalWay4Go() {
        carKeys.unlock();
        carDoors.open();
        engine.start();
        gear.setGear(1);
        parkingBrake.release();
        clutch.release();
        car.go();
    }
    
    @Test
    public void typicalWay4Stop() {
        clutch.push();
        gear.setGear(0);
        parkingBrake.hold();
        engine.stop();
        car.stop();
        carDoors.close();
        carKeys.lock();
        
    }
    
    @Test
    public void facadeWay4Go() {
        facade.go();
    }
    
    @Test
    public void facedeWay4Stop() {
        facade.stop();
    }

}

从类图你能够看到,7个组件类现在跟外观类是聚合关系,客户类现在不需要跟7个组件类打交道,它只需要跟掮客外观类打交道就好了,这种设计的好处是显而易见的:

  1. 客户端跟子系统松散耦合,子系统的改变不会造成客户端调用者的改变。

  2. 外观类可以根据需要更改算法(操作的顺序),客户端对这些改变是不知情的。

  3. 增加子系统或者替换子系统,对客户没有影响。

  4. 实践了最小知识原则。

上一篇 下一篇

猜你喜欢

热点阅读