什么是外观模式?
外观模式是一种结构型设计模式。
外观模式为子系统中的一组接口提供一个一致的入口,它定义了一个高层接口,这个接口使子系统更容易使用。
外观模式在实际生活中也很常见,比如说我们去Genius Bar维修电脑,正常修电脑需要排查问题,拆机,更换零件,组装,交付等流程,这些都是与客户没有任何关系的业务执行,所以Genius Bar合理的利用了外观设计模式,将维修电脑这一系列业务执行,封装起来,我们只需预约Genius Bar,提出问题,便自动调用了维修电脑的业务执行。
核心结构
- Facade。外观角色,它声明了对外调用的方法,在外观角色中,可以很明显知道子系统的数量和职责,它根据调用顺序执行子系统中的方法,从而完成整个业务执行。
- Subsystem。子系统角色,它主要是作用是封装了具体的业务实现,实际coding中,不仅外观模式可以调用子系统中的方法,其实外部对象也可以调用子系统中的方法。
类图展示
抽象外观模式是由外观模式演变而来,外观模式类图比较简单,故在此展示抽象外观模式类图,核心思想均一致。
代码分析
我们下面将对外观模式和抽象外观模式进行代码分析。
外观模式
在消息推送平台中,一条消息可以是Android透传消息、iOS通知和winPhone消息中的一种,它可能发送多种用户群中的一种,也可以通过不同的通道进行消息发送,这些消息的生产与发送过程,外部调用方是不需要了解的,他们只需要将消息信息传递进来即可,这时,我们就可以采用外观设计模式来实现业务。
首先,我们实现组装消息,选择推送人群,发送通道这三个业务:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——子系统
*/
public class Message {
public void message(String type) {
switch (type) {
case "Android":
System.out.println("It is a message belongs to android");
break;
case "iOS":
System.out.println("It is a message belongs to iOS");
break;
case "winPhone":
System.out.println("It is a message belongs to winPhone");
break;
default:
break;
}
}
}
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——子系统
*/
public class Group {
public void group(String type) {
switch (type) {
case "full" :
System.out.println("full amount push task");
break;
case "appoint" :
System.out.println("appiont push task");
break;
case "district" :
System.out.println("district push task");
break;
case "label" :
System.out.println("label push task");
break;
default :
break;
}
}
}
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——子系统
*/
public class Send {
public void send(String type) {
switch (type) {
case "personal":
System.out.println("send message by personal channel");
break;
case "third":
System.out.println("send message by the third party");
break;
case "apns":
System.out.println("send message by the apns");
break;
default:
break;
}
}
}
接下来我们就需要实现关键部件,外观角色:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——外观类
*/
public class PushFacade {
private Group group;
private Message message;
private Send send;
public PushFacade() {
group = new Group();
message = new Message();
send = new Send();
}
public void setGroup(String type) {
group.group(type);
}
public void setMessage(String type) {
message.message(type);
}
public void setSend(String type) {
send.send(type);
}
public static class Constants {
public static final String GROUP_FULL = "full";
public static final String GROUP_APPOINT = "appoint";
public static final String GROUP_DISTRICT = "district";
public static final String GROUP_LABEL = "label";
public static final String MESSAGE_ANDROID = "Android";
public static final String MESSAGE_IOS = "iOS";
public static final String MESSAGE_WIN_PHONE = "winPhone";
public static final String SEND_PERSONAL = "personal";
public static final String SEND_THIRD = "third";
public static final String SEND_APNS = "apns";
}
}
测试代码如下:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式测试
*/
public class FacadeTest {
public static void main(String[] args) {
facadeTest();
}
private static void facadeTest() {
try {
PushFacade facade = new PushFacade();
facade.setGroup(PushFacade.Constants.GROUP_FULL);
facade.setMessage(PushFacade.Constants.MESSAGE_ANDROID);
facade.setSend(PushFacade.Constants.SEND_THIRD);
facade.setGroup(PushFacade.Constants.GROUP_APPOINT);
facade.setMessage(PushFacade.Constants.MESSAGE_IOS);
facade.setSend(PushFacade.Constants.SEND_APNS);
} catch (Exception e) {
e.printStackTrace();
}
}
}
抽象外观模式
抽象外观模式的分析举例和外观模式的代码举例相同,仅是新增了一个个性化人群构建,由于和全量、地域、标签或指定人群冲突,所以我们新增了一个个性化人群子系统,用于系统扩展:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——子系统
*/
public class Group {
public void group(String type) {
switch (type) {
case "full" :
System.out.println("full amount push task");
break;
case "appoint" :
System.out.println("appiont push task");
break;
case "district" :
System.out.println("district push task");
break;
case "label" :
System.out.println("label push task");
break;
default :
break;
}
}
}
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
*/
public class PersonaliseGroup {
public void group(String type) {
switch (type) {
case "teenage":
System.out.println("teenage level");
break;
case "adult":
System.out.println("adult level");
break;
case "elder":
System.out.println("elder level");
break;
default:
break;
}
}
}
由于我们新增了一个个性化推送人群,为了符合开闭原则,我们需要重新声明一个外观角色,我们先对代码进行一次重构。
首先,声明一个外观角色抽象类:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——抽象外观类
*/
public abstract class AbstractPushFacade {
public abstract void setGroup(String type);
public abstract void setMessage(String type);
public abstract void setSend(String type);
}
接着我们声明两个外观角色:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——外观类
*/
public class PushFacade extends AbstractPushFacade {
private Group group;
private Message message;
private Send send;
public PushFacade() {
group = new Group();
message = new Message();
send = new Send();
}
@Override
public void setGroup(String type) {
group.group(type);
}
@Override
public void setMessage(String type) {
message.message(type);
}
@Override
public void setSend(String type) {
send.send(type);
}
public static class Constants {
public static final String GROUP_FULL = "full";
public static final String GROUP_APPOINT = "appoint";
public static final String GROUP_DISTRICT = "district";
public static final String GROUP_LABEL = "label";
public static final String MESSAGE_ANDROID = "Android";
public static final String MESSAGE_IOS = "iOS";
public static final String MESSAGE_WIN_PHONE = "winPhone";
public static final String SEND_PERSONAL = "personal";
public static final String SEND_THIRD = "third";
public static final String SEND_APNS = "apns";
}
}
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——外观类
*/
public class PersonalisePushFacade extends AbstractPushFacade {
private PersonaliseGroup group;
private Message message;
private Send send;
public PersonalisePushFacade() {
group = new PersonaliseGroup();
message = new Message();
send = new Send();
}
@Override
public void setGroup(String type) {
group.group(type);
}
@Override
public void setMessage(String type) {
message.message(type);
}
@Override
public void setSend(String type) {
send.send(type);
}
public static class Constants {
public static final String PERSONALISE_GROUP_FULL = "teenage";
public static final String PERSONALISE_GROUP_APPOINT = "adult";
public static final String PERSONALISE_GROUP_DISTRICT = "elder";
public static final String MESSAGE_ANDROID = "Android";
public static final String MESSAGE_IOS = "iOS";
public static final String MESSAGE_WIN_PHONE = "winPhone";
public static final String SEND_PERSONAL = "personal";
public static final String SEND_THIRD = "third";
public static final String SEND_APNS = "apns";
}
}
接下来还是消息构建和消息推送两个子系统:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——子系统
*/
public class Message {
public void message(String type) {
switch (type) {
case "Android":
System.out.println("It is a message belongs to android");
break;
case "iOS":
System.out.println("It is a message belongs to iOS");
break;
case "winPhone":
System.out.println("It is a message belongs to winPhone");
break;
default:
break;
}
}
}
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/13 0013.
* 外观模式——子系统
*/
public class Send {
public void send(String type) {
switch (type) {
case "personal":
System.out.println("send message by personal channel");
break;
case "third":
System.out.println("send message by the third party");
break;
case "apns":
System.out.println("send message by the apns");
break;
default:
break;
}
}
}
模式总结
优点
- 降低了外部调用与子系统之间的耦合度,子系统的业务实现变更不会影响外部调用。
- 抽象外观模式在一定程度上实现了开闭原则。
- 子系统之间的变动也不会互相影响。
- 由于外部调用仅知道外观角色,在一定程度上对子系统实现了保护。
缺点
- 子系统数量过多,可能会影响系统性能。
- 如果代码设计不当,可能会违背开闭原则。
适用场景
- 业务实现比较复杂,涉及模块较多,只需提供一个简单的对外接口。
- 外部调用与子系统之间的耦合度较高。
- 在层次化结构中,可以使用外观模式定义系统中的每一层入口,比如说三层架构。