一、外观模式的实现方式
外观模式的核心是通过封装复杂子系统的调用逻辑,为客户端提供一个统一的简单接口。以下是实现步骤及示例:
- 定义子系统类
子系统类负责实现具体功能,与外观类解耦。例如,家庭影院系统中的投影仪、音响等组件:
// 子系统接口
interface TheaterControl {void on();void off();void setVolume(int volume);
}
// 具体子系统实现
class Projector implements TheaterControl {public void on() { System.out.println("投影仪开启"); }public void off() { System.out.println("投影仪关闭"); }
}
class StereoSystem implements TheaterControl {public void on() { System.out.println("音响开启"); }public void off() { System.out.println("音响关闭"); }public void setVolume(int volume) { System.out.println("音量设为:" + volume); }
}
- 创建外观类
外观类聚合子系统对象,提供高层接口,协调子系统操作:
public class HomeTheaterFacade {private TheaterControl projector;private TheaterControl stereo;public HomeTheaterFacade() {this.projector = new Projector();this.stereo = new StereoSystem();}// 统一接口:观影模式public void watchMovie(String movie) {System.out.println("准备观看:" + movie);projector.on();stereo.on();stereo.setVolume(50);}
}
- 客户端调用
客户端通过外观类简化复杂操作:
public class Client {public static void main(String[] args) {HomeTheaterFacade facade = new HomeTheaterFacade();facade.watchMovie("Java设计模式实战");}
}
二、测试方法与Mockito框架应用
测试外观模式时,需验证其是否正确调用子系统方法。通过Mockito框架模拟子系统对象,确保外观类逻辑正确。
- 基础测试:验证子系统方法调用
import static org.mockito.Mockito.*;
import org.junit.Test;
public class HomeTheaterFacadeTest {@Testpublic void testWatchMovie() {// 创建Mock对象TheaterControl mockProjector = mock(Projector.class);TheaterControl mockStereo = mock(StereoSystem.class);// 创建外观类并注入Mock对象HomeTheaterFacade facade = new HomeTheaterFacade() {@Overridepublic TheaterControl getProjector() { return mockProjector; }@Overridepublic TheaterControl getStereo() { return mockStereo; }};// 执行外观方法facade.watchMovie("测试电影");// 验证子系统方法调用verify(mockProjector).on();verify(mockStereo).on();verify(mockStereo).setVolume(50);}
}
- 高级测试:异常处理与状态验证
模拟子系统异常,测试外观类的容错逻辑:
@Test
public void testWatchMovieWithException() {TheaterControl mockProjector = mock(Projector.class);when(mockProjector.on()).thenThrow(new RuntimeException("投影仪故障"));HomeTheaterFacade facade = new HomeTheaterFacade() {@Overridepublic TheaterControl getProjector() { return mockProjector; }};try {facade.watchMovie("测试电影");fail("预期抛出异常");} catch (RuntimeException e) {assertEquals("投影仪故障", e.getMessage());}
}
三、实现与测试的注意事项
- 实现最佳实践
- 单一职责:外观类仅负责协调子系统,避免包含业务逻辑。
- 接口隔离:子系统应通过接口与外观类交互,增强扩展性。
- 线程安全:若外观类被多线程访问,需同步关键方法。
- 测试关键点
- 覆盖所有子系统调用:确保每个子系统方法在测试中被验证。
- 模拟异常场景:测试子系统故障时外观类的容错机制。
- 避免过度模拟:仅Mock必要子系统,保留真实依赖以测试完整流程。
四、总结
外观模式通过封装复杂子系统的调用逻辑,显著降低客户端耦合度。实现时需遵循接口隔离与单一职责原则,测试时利用Mockito框架验证子系统交互。其核心价值在于简化接口设计,但需注意对开闭原则的潜在违背及测试复杂度问题。