标准 专业
多元 极客

设计模式实验室(8)——外观模式

什么是外观模式?

外观模式是一种结构型设计模式。

外观模式为子系统中的一组接口提供一个一致的入口,它定义了一个高层接口,这个接口使子系统更容易使用。

外观模式在实际生活中也很常见,比如说我们去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;
        }
    }
}

模式总结

优点

  • 降低了外部调用与子系统之间的耦合度,子系统的业务实现变更不会影响外部调用。
  • 抽象外观模式在一定程度上实现了开闭原则
  • 子系统之间的变动也不会互相影响。
  • 由于外部调用仅知道外观角色,在一定程度上对子系统实现了保护。

缺点

  • 子系统数量过多,可能会影响系统性能。
  • 如果代码设计不当,可能会违背开闭原则

适用场景

  • 业务实现比较复杂,涉及模块较多,只需提供一个简单的对外接口。
  • 外部调用与子系统之间的耦合度较高。
  • 在层次化结构中,可以使用外观模式定义系统中的每一层入口,比如说三层架构。
赞(2) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫