Java外观模式实现方式与测试方法

一、外观模式的实现方式

外观模式的核心是通过封装复杂子系统的调用逻辑,为客户端提供一个统一的简单接口。以下是实现步骤及示例:


  1. 定义子系统类
    子系统类负责实现具体功能,与外观类解耦。例如,家庭影院系统中的投影仪、音响等组件:
java 复制代码
// 子系统接口
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); }
}

  1. 创建外观类
    外观类聚合子系统对象,提供高层接口,协调子系统操作:
java 复制代码
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);
    }
}

  1. 客户端调用
    客户端通过外观类简化复杂操作:
java 复制代码
public class Client {
    public static void main(String[] args) {
        HomeTheaterFacade facade = new HomeTheaterFacade();
        facade.watchMovie("Java设计模式实战");
    }
}

二、测试方法与Mockito框架应用

测试外观模式时,需验证其是否正确调用子系统方法。通过Mockito框架模拟子系统对象,确保外观类逻辑正确。


  1. 基础测试:验证子系统方法调用
java 复制代码
import static org.mockito.Mockito.*;
import org.junit.Test;
public class HomeTheaterFacadeTest {
    @Test
    public void testWatchMovie() {
        // 创建Mock对象
        TheaterControl mockProjector = mock(Projector.class);
        TheaterControl mockStereo = mock(StereoSystem.class);
        
        // 创建外观类并注入Mock对象
        HomeTheaterFacade facade = new HomeTheaterFacade() {
            @Override
            public TheaterControl getProjector() { return mockProjector; }
            @Override
            public TheaterControl getStereo() { return mockStereo; }
        };
        
        // 执行外观方法
        facade.watchMovie("测试电影");
        
        // 验证子系统方法调用
        verify(mockProjector).on();
        verify(mockStereo).on();
        verify(mockStereo).setVolume(50);
    }
}

  1. 高级测试:异常处理与状态验证
    模拟子系统异常,测试外观类的容错逻辑:
java 复制代码
@Test
public void testWatchMovieWithException() {
    TheaterControl mockProjector = mock(Projector.class);
    when(mockProjector.on()).thenThrow(new RuntimeException("投影仪故障"));
    
    HomeTheaterFacade facade = new HomeTheaterFacade() {
        @Override
        public TheaterControl getProjector() { return mockProjector; }
    };
    
    try {
        facade.watchMovie("测试电影");
        fail("预期抛出异常");
    } catch (RuntimeException e) {
        assertEquals("投影仪故障", e.getMessage());
    }
}

三、实现与测试的注意事项

  1. 实现最佳实践
    • 单一职责:外观类仅负责协调子系统,避免包含业务逻辑。
    • 接口隔离:子系统应通过接口与外观类交互,增强扩展性。
    • 线程安全:若外观类被多线程访问,需同步关键方法。
  2. 测试关键点
    • 覆盖所有子系统调用:确保每个子系统方法在测试中被验证。
    • 模拟异常场景:测试子系统故障时外观类的容错机制。
    • 避免过度模拟:仅Mock必要子系统,保留真实依赖以测试完整流程。

四、总结

外观模式通过封装复杂子系统的调用逻辑,显著降低客户端耦合度。实现时需遵循接口隔离与单一职责原则,测试时利用Mockito框架验证子系统交互。其核心价值在于简化接口设计,但需注意对开闭原则的潜在违背及测试复杂度问题。