Facade pattern:外观模式(门面模式)
- The definition of facade pattern.
- How to use?
- Advantages and disadvantages.
Definition:隐藏子系统的复杂性,并向客户端提供了一个可以访问系统的接口。
外部与子系统的通信必须通过一个统一的门面对象进行。既提供了一个高层次的接口,使得子系统更容易使用。
这个对象知晓一个或多个子系统的功能和责任,在正常情况下,该对象会将所有从客户端发来的请求委派到相应的子系统。
现在有一个需求,画不同的形状。
1.我们创建一个画图的接口
public interface Shape{
void draw();
}
2.实现接口的实体类
public class Rectangle implements Shape{
public void draw(){
System.out.println("Rectangle:draw()");
}
}
public class Square implements Shape{
public void draw(){
System.out.println("Square:draw()");
}
}
public class Circle implements Shape{
public void draw(){
System.out.println("Circle:draw()");
}
}
3.画出各种类型的形状
Public class Client{
public static void main(String[] args){
Rectangle rectangle = new Rectangle();
Square square = new Square();
Circle circle = new Circle();
rectangle.draw();
square.draw();
circle.draw();
}
}
外界访问直接深入到子系统内部,相互之间是一种强耦合的关系,你死我就死,你活我才能活。
而门面模式所有的依赖都是对门面对象的依赖,与子系统无关。
外观模式:
创建一个外观类,这个类知晓子系统的所有功能和责任,它自己并没有实际的业务逻辑,只是一个委托类。
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();
}
}
然后客户端在与外观类交互。
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}
客户端不需要知道系统内部的复杂联系,整个系统只需要提供一个”接待员”即可。
这个例子可能不能很好的描述facade。我们来看下一个。
比如我们现实中写信,首先我们写信的内容,然后写地址和邮编,接着把信装进信封中,最后要投递在信箱中。这4个步骤,缺一不可,而且顺序不能颠倒,否则就会失败。
普通写法
1.写信的接口
public interface ILetterProcess{
public void writeContext(String context);
public void fillEnvelope(String address,String zipCode);
public void letterInotoEnvelope();
public void sendLetter();
}
2.接口的实现
public class LetterProcessImpl implements ILetterProcess{
public void writeContext(String context){
System.out.println(“填写信的内容…” + context);
}
public void fillEnvelope(String address,String zipCode){
System.out.println(“填写收件人地址及邮编…” + address + "&&" + zupCode);
}
public void letterInotoEnvelope(){
System.out.println(“把信放到信封中…”);
}
public void sendLetter(){
System.out.println(“邮递信件…” );
}
}
3.场景类
public class Client{
public static void main(){
ILetterProcess letterProcess = new LetterProcessImpl();
letterProcess.writeContext("Hello,It’s me,do you know who I am?I’m your old lover.I’d like to …");
letterProcess.fillEnvelope("Happy Road NO.666,God Province.Heaven","888");
letterProcess.letterInotoEnvelope();
letterProcess.sendLetter();
}
}
运行结果:
填写信的内容… Hello,It’s me,do you know who I am?I’m your old lover.I’d like to …
填写收件人的地址及姓名… Happy Road NO.666,God Province,Heaven&&888
把信放到信封中…
邮递信件…
普通的写法与高内聚的要求相差甚远,更不用说迪米特法则、接口隔离原则了。它根本没有完成一个类所具有的单一职责。
如果信件多了就非常麻烦,每封信都要运转一遍。
外观模式:
public class ModenPostOffice{
private ILetterProcess letterProcess = new ILetterProcess();
public void sendLetter(String context,String address,String zipCode){
letterProcess.writeContext(context);
letterProcess.fillEvenlope(address,zipCode);
letterProcess.letterInotoEnvelope();
letterProcess.sendLetter();
}
}
ModenPostOffice提供了一种新型服务,我们只要把信的内容和地址给他们,他们就会把信写好,封好,并发送出去。客户减少了很多工作。
我们来写门面模式下的场景类
public class Client{
public static void main(String[] args){
ModenPostOffice helloPostOffice = new ModenPostOffice();
String address = "Happy Road NO.666,God Province,Heaven";
String zipCode = "888";
String context = "Hello,It’s me,do you know who I am?I’m your old lover.I’d like to …";
helloPostOffice.sendLetter(context,address,zipCode);
}
}
运行结果是相同的,我们只需要与ModenPostOffice交互就成了,写信和写地址都可以不管,只需要将信的内容和地址提交过去就行了,邮局保证会按照我们指定的地址把指定的内容发送出去。
现在我们有一个需求,在一个非常时期,寄望BJ的邮件必须进行检查。
增加一个Police类
public class Police{
public void checkLetter(ILetterProcess letterProcess){
System.out.println(letterProcess + "信件已经检查过了");
}
}
对ModenPostOffice的扩展 即现代化的邮局
public class ModenPostOffice{
private ILetterProcess letterProcess = new LetterProcessImpl();
private Police letterPolice = new Police();
//写信,封装,投递,一体化
public void sendLetter(String context,String address){
//帮你写信
letterProcess.writeContext(context);
//写好信封
letterProcess.fillEnvelope(address);
//检查信件
letterPolice.checkLetter(letterProcess);
//把信放在信封中
letterPolice.letterInotoEnvelope();
//邮递信件
letterProcess,sendLetter();
}
}
只是增加了一个letterPolice变量的声明以及一个方法的调用,增加了一个检查信件,对客户来说是透明的,他根本看不到有人在检查他的邮件,他也不用了解,反正现代化的邮件系统都帮他做了。
场景类还是完全相同,但是运行结果稍微不同。
高层模块没有任何的改动,但是信件却已经被检查过了。
这真是我们设计所需要的模式,不改变子系统对外暴露的接口、方法,只改变内部的处理逻辑,其他兄弟模块的调用产生了不同的结果,确实是一个非常棒的结果。