外观(门面)模式(结构型模式)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27464169/article/details/89377003

门面模式这一篇就够了

简介

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。
不改变子系统对外暴露的接口、方法,只改变内部的处理逻辑。

概念
要求一个子系统外部与内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

主要解决

降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。

何时使用

  1. 客户端不需要知道系统内部的复杂联系,整个系统只需提供一个"接待员"即可。
  2. 定义系统的入口。

关键代码
在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。

应用实例

  1. 去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便。
  2. JAVA 的三层开发模式。
  3. 古代写信邮信自己处理,现代由邮局处理。

优点

1. 减少系统的相互依赖:如果不使用门面模式,外界访问直接深入到子系统内部,相互之间是强耦合关系,门面模式解决了这种关系,所有依赖都是对门面对象的依赖,与子系统无关。
2. 灵活性提高:依赖减少,灵活性自然提高。不管系统内部如何变化,只要不影响门面对象就好。
3. 安全性提高:可以根据子系统需要访问的业务,开通门面类的方法(可以有多个门面类,每个门面类向外界提供不同的业务接口),不开通的访问不到,提高了安全性。

缺点

不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

使用场景

1. 为复杂的模块或子系统提供外界访问的模块
2. 子系统相对独立——外界对子系统访问只需黑箱操作即可:比如利息计算问题,需要扎实的技术水平和业务处理能力才能开发出来,但是对于使用系统的开发人员来说,需要做的就是输入金额以及存期,其他的不用关心,返回结果就是利息,这时候可以使用门面模式。
3. 预防低水平人员带来的风险:在指定的子系统中开发,然后再提供门面接口进行访问操作。

注意事项

在层次化结构中,可以使用外观模式定义系统中每一层的入口
(通俗的讲,就是一个子系统可以有多个门面)
什么情况下需要多个门面?

  • 门面类臃肿
  • 子系统可以提供不能访问路径

最佳实现(摘自设计模式之禅-门面模式通用源码部分)
类图:
门面模式
门面模式示意图

门面对象是外界访问子系统内部唯一通道
Facade门面角色:本角色将所有从可无端发出来的请求委派到相应的子系统中,该角色没有实际的业务逻辑,只是一个委托类
subsystem子系统角色:可以一个或多个,子系统不知道门面系统的存在,对于子系统而言,门面仅仅只是另外一个客户端。

通用代码

子系统

public class ClassA {
	public void doSomethingA() {
	}
}
public class ClassB {
	public void doSomethingB() {
	}
}
public class ClassC {
	public void doSomethingC() {
	}
}

门面角色

public class Facade {
	// 被委托的对象
	private ClassA a = new ClassA();
	private ClassB b = new ClassB();
	private ClassC C = new ClassC();
	// 提供外部访问的方法
	public void doSomethingA() {
		this.a.doSomethingA();
	}

	public void doSomethingB() {
		this.b.doSomethingB();
	}

	public void doSomethingC() {
		this.c.doSomethingC();
	}
}

延伸:
门面类不应当参与子系统内的逻辑
以通用源码为例,将methodc()方法增加逻辑,先调用a.doSomethingA()。

public class Facade {
	// 被委托的对象
	private ClassA a = new ClassA();
	private ClassB b = new ClassB();
	private ClassC C = new ClassC();
	// 提供外部访问的方法
	public void doSomethingA() {
		this.a.doSomethingA();
	}

	public void doSomethingB() {
		this.b.doSomethingB();
	}

	public void methodc() {
		this.a.doSomethingA();
		this.c.doSomethingC();
	}
}

这样设计很不合理,因为门面对象参与了业务逻辑,门面对象应当只提供一个访问子系统路径而不应该参与具体业务逻辑,违反了单一原则,也破坏了封装性。
正确处理:

// 封装类
public class Context {
	// 委托的对象
	private ClassA a = new ClassA();
	private ClassC C = new ClassC();
	// 复杂的计算
	public void complexMethod() {
		this.a.doSomethingA();
		this.c.doSomethingC();
	}
}
public class Facade {
	// 被委托的对象
	private ClassA a = new ClassA();
	private ClassB b = new ClassB();
	private Context context = new Context();
	// 提供外部访问的方法
	public void doSomethingA() {
		this.a.doSomethingA();
	}

	public void doSomethingB() {
		this.b.doSomethingB();
	}

	public void methodc() {
		this.context.complexMethod();
	}
}

记住一句话:门面角色应该稳定,而不应该经常变化,它是一个系统对外的接口,尽可能保证稳定!

最佳实践:
门面模式是很好的封装方法,一个子系统比较复杂或算法、业务复杂时,可以封装出多个门面,结构简单,扩展性好,还能规避风险。

创作不易,写个博客不容易,希望路过的各位同胞点个赞,或者评论、关注下!你的支持是我写博客的最大动力!点个赞就行!
如果你想接点程序相关的小活(范围:400元-2000元,土豪可绕行),可以加上我的QQ号(75975175),我这边有机会向您免费提供私活资源,供您参考!

猜你喜欢

转载自blog.csdn.net/qq_27464169/article/details/89377003