外觀模式(Facade)
在現(xiàn)實生活中,常常存在辦事較復雜的例子,如辦房產(chǎn)證或注冊一家公司,有時要同多個部門聯(lián)系,這時要是有一個綜合部門能解決一切手續(xù)問題就好了。
軟件設(shè)計也是這樣,當一個系統(tǒng)的功能越來越強,子系統(tǒng)會越來越多,客戶對系統(tǒng)的訪問也變得越來越復雜。這時如果系統(tǒng)內(nèi)部發(fā)生改變,客戶端也要跟著改變,這違背了“開閉原則”,也違背了“迪米特法則”,所以有必要為多個子系統(tǒng)提供一個統(tǒng)一的接口,從而降低系統(tǒng)的耦合度,這就是外觀模式的目標。
外觀模式的定義與特點
外觀(Facade)模式的定義:
是一種通過為多個復雜的子系統(tǒng)提供一個一致的接口,而使這些子系統(tǒng)更加容易被訪問的模式。該模式對外有一個統(tǒng)一接口,外部應(yīng)用程序不用關(guān)心內(nèi)部子系統(tǒng)的具體的細節(jié),這樣會大大降低應(yīng)用程序的復雜度,提高了程序的可維護性。外觀(Facade)模式的優(yōu)點:
1.降低了子系統(tǒng)與客戶端之間的耦合度,使得子系統(tǒng)的變化不會影響調(diào)用它的客戶類。
2.對客戶屏蔽了子系統(tǒng)組件,減少了客戶處理的對象數(shù)目,并使得子系統(tǒng)使用起來更加容易。
3.降低了大型軟件系統(tǒng)中的編譯依賴性,簡化了系統(tǒng)在不同平臺之間的移植過程,因為編譯一個子系統(tǒng)不會影響其他的子系統(tǒng),也不會影響外觀對象。外觀(Facade)模式的缺點:
1.不能很好地限制客戶使用子系統(tǒng)類。
2.增加新的子系統(tǒng)可能需要修改外觀類或客戶端的源代碼,違背了“開閉原則”。
外觀模式的結(jié)構(gòu)與實現(xiàn)
外觀(Facade)模式的結(jié)構(gòu)比較簡單,主要是定義了一個高層接口。它包含了對各個子系統(tǒng)的引用,客戶端可以通過它訪問各個子系統(tǒng)的功能?,F(xiàn)在來分析其基本結(jié)構(gòu)和實現(xiàn)方法。
1. 模式的結(jié)構(gòu)
外觀(Facade)模式包含以下主要角色。
- 外觀(Facade)角色: 為多個子系統(tǒng)對外提供一個共同的接口。
- 子系統(tǒng)(Sub System)角色: 實現(xiàn)系統(tǒng)的部分功能,客戶可以通過外觀角色訪問它。
- 客戶(Client)角色:通過一個外觀角色訪問各個子系統(tǒng)的功能。
其結(jié)構(gòu)圖如圖 2 所示。

2. 模式的實現(xiàn)
外觀模式的實現(xiàn)代碼如下:
package facade;
public class FacadePattern
{
public static void main(String[] args)
{
Facade f=new Facade();
f.method();
}
}
//外觀角色
class Facade
{
private SubSystem01 obj1=new SubSystem01();
private SubSystem02 obj2=new SubSystem02();
private SubSystem03 obj3=new SubSystem03();
public void method()
{
obj1.method1();
obj2.method2();
obj3.method3();
}
}
//子系統(tǒng)角色
class SubSystem01
{
public void method1()
{
System.out.println("子系統(tǒng)01的method1()被調(diào)用!");
}
}
//子系統(tǒng)角色
class SubSystem02
{
public void method2()
{
System.out.println("子系統(tǒng)02的method2()被調(diào)用!");
}
}
//子系統(tǒng)角色
class SubSystem03
{
public void method3()
{
System.out.println("子系統(tǒng)03的method3()被調(diào)用!");
}
}
程序運行結(jié)果如下:
子系統(tǒng)01的method1()被調(diào)用!
子系統(tǒng)02的method2()被調(diào)用!
子系統(tǒng)03的method3()被調(diào)用!
外觀模式的實例
我們將創(chuàng)建一個 Shape 接口和實現(xiàn)了 Shape 接口的實體類。下一步是定義一個外觀類 ShapeMaker。
ShapeMaker 類使用實體類來代表用戶對這些類的調(diào)用。FacadePatternDemo,我們的演示類使用 ShapeMaker 類來顯示結(jié)果。

1.創(chuàng)建一個接口。Shape.java
public interface Shape {
void draw();
}
2.創(chuàng)建實現(xiàn)接口的實體類。Rectangle.java、Square.java、Circle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle::draw()");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square::draw()");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
3.創(chuàng)建一個外觀類。ShapeMaker.java
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}
4.使用該外觀類畫出各種類型的形狀。FacadePatternDemo.java
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}
程序運行結(jié)果如下:
子系統(tǒng)01的method1()被調(diào)用!
子系統(tǒng)02的method2()被調(diào)用!
子系統(tǒng)03的method3()被調(diào)用!
外觀模式的應(yīng)用場景
- 對分層結(jié)構(gòu)系統(tǒng)構(gòu)建時,使用外觀模式定義子系統(tǒng)中每層的入口點可以簡化子系統(tǒng)之間的依賴關(guān)系。
- 當一個復雜系統(tǒng)的子系統(tǒng)很多時,外觀模式可以為系統(tǒng)設(shè)計一個簡單的接口供外界訪問。
- 當客戶端與多個子系統(tǒng)之間存在很大的聯(lián)系時,引入外觀模式可將它們分離,從而提高子系統(tǒng)的獨立性和可移植性。
外觀模式的擴展
在外觀模式中,當增加或移除子系統(tǒng)時需要修改外觀類,這違背了“開閉原則”。如果引入抽象外觀類,則在一定程度上解決了該問題,其結(jié)構(gòu)圖如下圖所示。
