外观模式
,为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这个子系统更加容易使用。
假如我们开车上班,为了使车子走起来我们要做些什么操作?假设我们开的是手动挡的车,我们需要按这个步骤来操作:
-
用遥控钥匙解锁车门
-
打开车门
-
关上车门
-
启动发动机
-
挂挡
-
松手刹
-
松离合器
-
车子开始走
如果用java代码来描述这一系列的动作该怎样设计呢?很显然,我们需要几个类,而每个类都有自己的一些行为,我先用UML类图来描述一下这些类以及它们的行为。
![](https://img.haomeiwen.com/i1527003/0fa3a2fd854d7c3d.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个类及它们的行为,但是从这种设计里面我们看到一些弊端:
- 车子的启动顺序由客户决定,但是万一客户弄错了呢?例如还没有按遥控钥匙就去开车门或是发动机还没有启动就挂挡。或者更糟糕的情况,客户根本就没有调用松离合器的方法。
- 现在7个组件跟客户都是聚合关系,如果这7个组件类里面有关于行为方法的改动(例如参数列表的变化)就势必要更改客户端的调用代码。
从以上两个缺点来看,我觉得这种设计是紧耦合并且是脆弱的。试想有一天,客户希望他的汽车能够自动驾驶,他不想要每天重复这么多繁琐的动作,他想要的就是按一下汽车钥匙的go按钮然后汽车把剩下的所有步骤都完成,他只要下车去办公室就好了。
那么如何解决这种问题?
为了解决这种问题,我们需要引入外观模式
,也有的称之为门面模式
。门面模式的定义是这样的:外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
外观模式也诠释了面向对象设计原则中的迪米特法则
(最少知识原则),最少知识意指一个类应该只跟它需要打交道的类沟通,这样可以有效的保证松散耦合
![](https://img.haomeiwen.com/i1527003/adf0689e6721d3f2.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个组件类打交道,它只需要跟掮客外观类打交道就好了,这种设计的好处是显而易见的:
-
客户端跟子系统松散耦合,子系统的改变不会造成客户端调用者的改变。
-
外观类可以根据需要更改算法(操作的顺序),客户端对这些改变是不知情的。
-
增加子系统或者替换子系统,对客户没有影响。
-
实践了最小知识原则。
网友评论