该系列文章为博主学习笔记,原文请参考参考连接
本文禁止转载,但是欢迎大家留言区留言交流[微笑]
外观模式是开发中很常见的模式,比如在每一个界面中我们都需要对界面的标题栏进行初始化返回键,初始化标题,初始化标题栏的背景颜色。
流程就是以上的流程,我们落实到代码中:
//初始化返回键
public class InitBack {
public void initBack(){
System.out.println("初始化返回键");
}
}
//初始化标题
public class InitInternetTitle {
public void initTitle(){
System.out.println("通过网络请求初始化标题");
}
}
//初始化背景色
public class InitBackground {
public void initBackground(){
System.out.println("初始化背景色");
}
}
public class MyClass {
private InitBack initBack=new InitBack();
private InitBackground initBackground=new InitBackground();
private InitInternetTitle initTitle=new InitInternetTitle ();
public static void main(String[] args) {
MyClass myClass=new MyClass();
myClass.initBack.initBack();
myClass.initBackground.initBackground();
myClass.initTitle.initTitle();
}
}
输出:
初始化返回键
初始化背景色
初始化标题
这样写的最大的缺点就是客户端对业务类保留了大量的引用,当业务类进行增加或者删除等操作,需要对客户端的代码进行改动,这违反了开闭原则。
我们进行下一步改进,让客户端引用较少的成员变量,将业务逻辑都放在一个Facade类(外观类)中,这样客户端就没有必要知道,业务类都有什么操作,这些操作都是做了什么,只需要对这个Facade类进行编程即可。
public class Facade {
private InitBack initBack=new InitBack();
private InitBackground initBackground=new InitBackground();
private InitInternetTitle initTitle=new InitInternetTitle ();
public void initView(){
initBack.initBack();
initBackground.initBackground();
initTitle.initTitle();
}
}
public class MyClass {
public static void main(String[] args) {
Facade facade=new Facade();
facade.initView();
}
}
从上面的解决方案看起来觉得很完美了,但如果现在的需求变成了要将初始化标题类改成另外一个类InitNativeTitle ,从本地Xml文件中读取,这样就会面临两方面的修改:
1.修改Facade类中对初始化标题类的引用,将InitInternetTitle改为InitNativeTitle类的引用。
2.创建一个新的NewFacade类,保持对InitBack、InitBackground 、InitNativeTitle 的引用,并且修改客户端的MyClass类保持对NewFacade类的引用。
但是不管从上面哪个解决方案来看都都会对客户端以及外观类进行更改违反了开闭原则。
所以针对以上的情况引入了抽象外观类,让多个外观类继承抽象外观类,这样在客户端中可以直接引用抽象类,在配置文件中指定运行中具体的外观类。
public abstract class AbstractFacade {
public abstract void doSomething();
}
public class Facade extends AbstractFacade{
private InitBack initBack=new InitBack();
private InitBackground initBackground=new InitBackground();
private InitInternetTitle initTitle=new InitInternetTitle ();
@Override
public void doSomething() {
initBack.initBack();
initBackground.initBackground();
initTitle.initTitle();
}
}
//新增加的外观类
public class NewFacade extends AbstractFacade{
private InitBack initBack=new InitBack();
private InitBackground initBackground=new InitBackground();
private InitNativeTitle initTitle=new InitNativeTitle ();
@Override
public void doSomething() {
initBack.initBack();
initBackground.initBackground();
initTitle.initTitle();
}
}
//新增加的初始化标题类——从本地读取
public class InitNativeTitle {
public void initTitle(){
System.out.println("通过本地读取文件初始化标题");
}
}
public class InitBackground {
public void initBackground(){
System.out.println("初始化背景色");
}
}
public class InitInternetTitle {
public void initTitle(){
System.out.println("通过网络请求初始化标题");
}
}
public class InitBack {
public void initBack(){
System.out.println("初始化返回键");
}
}
//config.properties
name=com.example.lib.NewFacade
public class myClass {
public static void main(String[] args){
AbstractFacade abstractFacade;
Properties properties=new Properties();
InputStream inputStream=null;
try {
inputStream=new FileInputStream("E:\\MyApplication\\lib\\src\\main\\java\\com\\example\\lib\\config.properties");
properties.load(inputStream);
String name=properties.getProperty("name");
System.out.println("name = " + name);
Class classz = Class.forName(name);
Constructor c1=classz.getDeclaredConstructor();
abstractFacade = (AbstractFacade) c1.newInstance();
abstractFacade.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
}
}
这样就可以通过配置文件去更改客户端对配置文件的引用,客户端不对子系统进行引用,不知道子系统都做了什么,同样子系统的更改更不会影响客户端的更改,子系统之间的修改也不会影响到其他的子系统。
但是同样也有些缺点,此种设计还是有一定的局限性,针对一些固有的操作很方便,比如经常做一些固定的操作,可以使客户端和子系统进行隔离,但是如果我们要经常增加或者删除一些子系统,这样我们还得对外观类进行更改,这还是违反了开闭原则。