经典设计模式——门面模式

简介:

   随着系统的不断改进和开发的深入,它们会变得越来越复杂,系统会生成大量的类,这使得程序更难被理解。门面模式可谓这些类提供一个简化的接口,从而简化访问这些类的复杂性,有时候这种简化可能降低访问这些底层累的灵活性,但除了要求特别苛刻的客户端之外(即调用方法的类),它通常都可以提供所需的全部功能。当然,那些苛刻的客户端仍然可以直接访问底层的类和方法。

    门面(Facade)模式也被称为正面模式、外观模式,这种模式用于将一组复杂的类包装到一个简单的外部接口中。

    现在考虑这样的场景:我们有一个顾客需要到饭店用餐,这就需要定义一个Customer类,并为该类定义一个haveDinner方法。假设该饭店有三个部门:收银部、厨师部和服务生部,用户就餐需要这三个部门协调才能完成。本示例程序先定义一个收银部,用户需要调用该部门的pay方法:

?
1
2
3
4
5
6
7
public  class  PaymentImpl  implements  Payment {
     public  String pay( double  price) {
         String food =  "快餐"
         System.out.println( "您已付款:"  + price +  "元,购买的是:"  + food);
         return  food;
     }
}

    接下来定义厨师部门:

?
1
2
3
4
5
public  class  CookImpl  implements  Cook {
     public  String cook(String food) {
         System.out.println( "厨师正在烹调:"  + food);
     }
}

    服务生部门:

?
1
2
3
4
5
public  class  WaiterImpl  implements  Waiter {
     public  void  serve(String food) {
         System.out.println( "服务员正在端菜:"  + food);
     }
}

    接下来实现Customer类的haveDinner方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  class  Customer {
     public  void  haveDinner() {
         //依次创建三个部门
         Payment payment =  new  PaymentImpl();
         Cook cook =  new  CookImpl();
         Waiter waiter =  new  WaiterImpl();
         //依次调用三个部门的不同方法
         String food = payment.pay();
         cook.cook(food);
         waiter.serve(food);
         //直接依赖于Facade类来实现用餐方法
         Facade f =  new  Facade();
         f.serveFood();
     }
}

    正如上面的代码所示,Customer需要依次调用三个部门的方法才能完成这个haveDinner方法,实际上,如果这个饭店有更多的部门,那么程序就需要调用更多部门的方法来实现这个haveDinner方法——这就会增加haveDinner方法的实现难度了。

    为了解决这个问题,我们可以为Payment、Cook、Waiter三个部门提供一个门面(Facade),使用Facade来包装这些类,对外提供一个简单的访问方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public  class  Facade() {
     //定义被封装的三个部门
     Payment payment;
     Cook cook;
     Waiter waiter;
     //构造函数
     public  Facade(Payment payment, Cook cook, Waiter waiter) {
         this .payment = payment;
         this .cook = cook;
         this .waiter = waiter;
     }
     public  void  serveFood() {
         String food = payment.pay();
         cook.cook(food);
         waiter.serve(food);
     }
}

    从Facade代码可以看出,该门面保证了Payment,Cook和Waiter三个部门,程序对外提供了一个简单的serveFood方法,该方法对外提供了一个用餐的方法,而底层则依赖于三个部门的pay(),cook(),serve()三个方法。一旦程序提供了这个门面类Facade后,Customer类实现haveDinner方法就变得更加简单了,下面是通过Facade类实现的haveDinner方法:

?
1
2
3
4
public  void  haveDinner() {
     Facade f =  new  Facade();
     f.serveFood();
}

    从上面的结构可以看出,如果不采用门面模式,客户端需要自行决定需要调用哪些类、哪些方法,并需要按合理的顺序来调用它们才能实现所需的功能。不采用门面模式时,程序有如图所示的结构:

        然而,使用了门面模式之后,客户端代码只需要和门面类进行交互即可,于是,程序结构图变成了如下样式:

    其实,Spring的HibernateTemplate类就是使用的门面模式:当我们的程序使用Hibernate的find()方法时,程序只要一行代码即可得到查询返回的List。但实际上该find()方法后隐藏了如下代码:

?
1
2
3
4
5
6
Session session = sf.openSession();
Query query = session.createQuery(hql);
for ( int  i= 0 ; i<args.length; i++) {
     query.setParameter(i, args[i]);
}
query.list();

    因此我们可以认为HibernateTemplate是SessionFactory,Session、Query等类的门面。当客户端程序需要进行持久化查询时,程序无需调用这些类,而是直接调用HibernateTemplate门面类中的相印方法即可。

    除此之外,JavaEE应用里使用业务逻辑组件来封装DAO组件也是典型的门面模式——每个业务逻辑组件(一般是Service层)都是众多DAO组件的门面,系统的控制器类无需直接访问DAO组件,而是由业务逻辑方法来组合多个DAO方法以完成所需功能。而Action只需与业务逻辑组件交互即可。


目录
相关文章
|
设计模式 算法
设计模式7 - 门面模式【Facade Pattern】
设计模式7 - 门面模式【Facade Pattern】
63 1
|
设计模式 算法 C++
设计模式之门面模式(C++)
设计模式之门面模式(C++)
|
7月前
|
设计模式 Java 应用服务中间件
设计模式 -结构型模式_门面模式(外观模式) Facade Pattern 在开源软件中的应用
设计模式 -结构型模式_门面模式(外观模式) Facade Pattern 在开源软件中的应用
66 1
|
7月前
|
设计模式
设计模式 | 门面模式 Facade
设计模式 | 门面模式 Facade
57 0
|
7月前
|
设计模式 传感器
将设计模式门面模式运用到生活当中
将设计模式门面模式运用到生活当中
|
设计模式
设计模式系列教程(10) - 外观模式(门面模式)
设计模式系列教程(10) - 外观模式(门面模式)
105 0
|
设计模式 Java
设计模式~门面(外观)模式(Facade)-08
目录 (1)优点 (2)缺点 (3)使用场景 (4)注意事项: (5)应用实例: (6)源码中的经典应用 代码 外观模式(Fac
62 0
|
设计模式
设计模式~门面模式-05
门面模式 优点 缺点 使用场景
49 0
|
设计模式
设计模式 | 门面模式 Facade
设计模式 | 门面模式 Facade
74 0
|
设计模式 Python
Python:设计模式之门面模式
Python:设计模式之门面模式
92 0