设计模式 10
- 创建型模式(5):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
- 结构型模式(7):适配器模式、桥接模式、组合模式、装饰者模式、外观模式、享元模式、代理模式
- 行为型模式(11):责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式
文章目录
- 设计模式 10
- 外观模式(Facade Pattern)
- 1 定义
- 2 结构
- 3 示例代码
- 4 特点
- 5 适用场景
- 6 与其他模式的关系
外观模式(Facade Pattern)
1 定义
外观模式通过为复杂的子系统提供一个简化的接口,使得客户端可以通过这个接口访问子系统的功能,而不需要直接与子系统的多个组件进行交互。外观模式可以隐藏子系统的复杂性,并且使得子系统与客户端的耦合度降低。
2 结构
外观模式的结构包含以下角色:
- 外观(Facade): 提供一个简化的接口,封装子系统的复杂性,供客户端调用。
- 子系统(Subsystem Classes): 子系统中的多个类,它们实现了子系统的实际功能。子系统可以有多个类,客户端可以直接访问它们,但通过外观类访问会更简单。
UML 类图
+-------------------+| Client |+-------------------+^|
+-------------------+ +-------------------+ +-------------------+
| SubsystemA | ----> | Facade | <---- | SubsystemC |
+-------------------+ +-------------------+ +-------------------+^ ^| |+-------------------+ +-------------------+| SubsystemB | | SubsystemD |+-------------------+ +-------------------+
3 示例代码
以下是一个实现外观模式的简单示例。在这个示例中,我们构建了一个家庭影院系统,客户端通过外观类 HomeTheaterFacade
来控制各个子系统,如电视、音响、灯光等。
子系统类
// 子系统类:电视
public class Television
{public void On(){Console.WriteLine("Television is on.");}public void Off(){Console.WriteLine("Television is off.");}
}// 子系统类:音响
public class SoundSystem
{public void On(){Console.WriteLine("Sound system is on.");}public void Off(){Console.WriteLine("Sound system is off.");}public void SetVolume(int volume){Console.WriteLine($"Sound system volume set to {volume}.");}
}// 子系统类:灯光
public class Lights
{public void Dim(int level){Console.WriteLine($"Lights dimmed to {level}%.");}public void On(){Console.WriteLine("Lights are on.");}
}
外观类
// 外观类:家庭影院
public class HomeTheaterFacade
{private readonly Television _television;private readonly SoundSystem _soundSystem;private readonly Lights _lights;public HomeTheaterFacade(Television television, SoundSystem soundSystem, Lights lights){_television = television;_soundSystem = soundSystem;_lights = lights;}public void WatchMovie(){Console.WriteLine("Get ready to watch a movie...");_lights.Dim(30);_television.On();_soundSystem.On();_soundSystem.SetVolume(5);}public void EndMovie(){Console.WriteLine("Shutting movie theater down...");_television.Off();_soundSystem.Off();_lights.On();}
}
客户端代码
class Program
{static void Main(string[] args){// 创建子系统对象Television television = new Television();SoundSystem soundSystem = new SoundSystem();Lights lights = new Lights();// 创建外观对象HomeTheaterFacade homeTheater = new HomeTheaterFacade(television, soundSystem, lights);// 使用外观模式控制子系统homeTheater.WatchMovie();Console.WriteLine("\nMovie is running...\n");homeTheater.EndMovie();}
}
在这个例子中:
Television
、SoundSystem
、Lights
是子系统类,提供了各自的功能。HomeTheaterFacade
是外观类,它将各个子系统的操作封装成了WatchMovie()
和EndMovie()
两个简单的方法,客户端只需调用这些方法即可控制整个家庭影院系统。- 客户端
Program
通过HomeTheaterFacade
类来控制整个家庭影院的各个设备,而不需要直接与每个设备交互。
4 特点
-
优点:
-
简化接口: 提供一个简化的接口来访问复杂的子系统,减少客户端与子系统之间的耦合。
-
隐藏子系统的复杂性: 客户端不需要了解子系统的内部结构,只需要与外观类交互即可。
-
减少依赖: 客户端与子系统之间的依赖关系减少,如果子系统发生变化,只需修改外观类,而不需要修改客户端代码。
-
-
缺点:
-
不符合开闭原则: 如果要扩展外观类的功能,可能需要修改外观类的代码,从而违反开闭原则。
-
潜在性能问题: 外观模式可能会因为封装了大量子系统的调用,而引入一定的性能开销。
-
5 适用场景
- 简化复杂系统的使用: 当系统内部结构复杂,客户端希望能够通过简单的接口使用系统时,使用外观模式非常合适。
- 解耦客户端与子系统: 当你希望减少客户端与多个子系统之间的依赖关系时,可以使用外观模式。
- 构建库或框架: 当你构建一个复杂库或框架,并希望提供一个简洁的接口供外部使用时,外观模式可以帮助你设计这个接口。
6 与其他模式的关系
- 与适配器模式的区别: 适配器模式是为了将一个接口转换为客户端期望的接口,而外观模式是为了提供一个简化的接口来使用复杂系统。适配器模式专注于接口兼容性,而外观模式专注于简化系统的使用。
- 与桥接模式的区别: 桥接模式用于将抽象与实现分离,使得它们可以独立变化,而外观模式关注于简化接口。
- 与单例模式的结合: 在某些情况下,外观类可以设计成单例,以确保客户端使用的是同一个外观对象。
外观模式通过提供一个统一和简化的接口来隐藏系统的复杂性,使得客户端能够更轻松地使用系统,同时保持系统内部结构的灵活性和可扩展性。