美文网首页设计模式
设计模式实践-外观模式

设计模式实践-外观模式

作者: h2coder | 来源:发表于2020-10-19 07:43 被阅读0次

    什么是外观模式?什么时候用?

    外观模式,也称为门面模式。其实日常生活中,有很多外观模式的影子,例如我们日常工作中,领导层,决定要开发一个直播模块,领导层给中层(部门老大)发出命令,中层则分配到特定的执行层(我们开发)。领导层无需知道下面的人是怎么分配的,谁和谁配合,只要发出命令,验收结果即可。

    场景

    • 例如刚完成的直播间模块,用户角色的改变,UI界面上很多部件的状态、样式、点击事件等都需要切换,这篇文章就不一一列举了,不是本文重点,避免跑题。

    • 直播间总共有以下角色:

      1. 普通用户
      2. 上座用户
      3. 房管
      4. 老师(主播)
      5. 禁言用户
      6. 游客
    直播间样式.png
    • 可以看到直播间的角色是非常多的,也不排除以后会增加其他角色,例如其他pk、助场老师等。这就涉及到了角色切换,切换的地方又不止一处,有的是由接口调用回调时切换,有的是IM触发而切换等等...那么需要切换的组件大于3个以上,每处都需要写相同的代码,而后续再加组件也需要切换时,就需要每处都要修改,这时就可以使用外观模式来统一分发切换,外部调用方无需知道哪些组件需要进行切换,只需要做要发起切换的动作行为即可。

    怎么实现外观模式?

    • Facade,门面接口,对外提供的Api接口。
    • 子系统接口,每个子系统都需要实现。

    外观模式实践,统一处理直播间角色改变

    如果正常逻辑去编写我们的代码,就会有非常多的if-else,所以每个UI组件我都用状态模式封装了一遍,外部只需要调用切换角色API即可,无需关注内部是怎么切换的,是显示、隐藏还是Remove、Add。而角色改变的时机并不是只有一处,那么调用各个组件的切换方法就会到处都是,为了解决这种情况我们使用外观模式,统一调用外观,外观再分发给每个需要角色切换的组件。

    实现步骤

    1. IRoleSwitcher接口,角色切换接口,定义了每种角色的切换方法,这里由于我们的门面和其他组件的操作是一样的,所以合并给一个接口。

    2. Component接口,子系统接口,定义通用组件方法,每个子系统都会自己有一个接口继承它,并提供子系统的特定Api。

    3. IBottomBarComponent,底部栏组件接口,实现了Component接口和IRoleSwitcher接口。

    4. IApplyForSeatComponent,上座按钮组件接口,实现了Component接口和IRoleSwitcher接口。

    5. IToolBoxComponent,辅助工具栏组件接口,实现了Component接口和IRoleSwitcher接口。

    6. IRoleComponent,角色组件,就是我们外观,Facade,负责分发切换事件给上面的3个组件,由于我们门面Api和子系统Api是一致的,所以本身也实现了IRoleSwitcher操作接口。同样实现了Component作为组件使用。(非必须,只是我们的场景比较简单,基本就是分发切换事件,而其他需要不同子系统配合的场景,门面Api一般和子系统是不一样的)

    别废话,上代码~

    • Component组件接口和IRoleSwitcher接口。
    public interface Component {
    }
    
    public interface IRoleSwitcher {
        /**
         * 设置为普通用户角色
         */
        void setNormalUserRole();
    
        /**
         * 设置为管理员角色
         */
        void setManagerRole();
    
        /**
         * 设置为上座用户角色
         */
        void setSeatUpRole();
    
        /**
         * 设置为老师角色
         */
        void setTeacherRole();
    
        /**
         * 设置为游客角色
         */
        void setVisitorRole();
    
        /**
         * 设置为游客禁言角色
         */
        void setForbidSpeakRole();
    }
    
    • IBottomBarComponent,底部栏组件接口和实现类
    public interface IBottomBarComponent extends Component, IRoleSwitcher {
        //...其他Api方法,不是重点
    }
    
    public class BottomBarComponent extends BaseRoomComponent implements IBottomBarComponent {
        @Override
        public void setNormalUserRole() {
            //底部栏切换到普通用户角色样式
            ...
        }
    
        @Override
        public void setManagerRole() {
            //底部栏切换到普通用户角色样式
            ...
        }
    
        @Override
        public void setSeatUpRole() {
            //底部栏切换到上座用户角色样式
            ...
        }
    
        @Override
        public void setTeacherRole() {
            //底部栏切换到老师用户角色样式
            ...
        }
    
        @Override
        public void setVisitorRole() {
            //底部栏切换到游客角色样式
            ...
        }
    
        @Override
        public void setForbidSpeakRole() {
            //底部栏切换到禁言用户角色样式
            ...
        }
    }
    
    • IApplyForSeatComponent,上座按钮组件
    public interface IApplyForSeatComponent extends Component, IRoleSwitcher {
            //...省略其他Api
    }
    
    public class ApplyForSeatComponent extends BaseRoomComponent implements IApplyForSeatComponent {
            //...实现方法和BottomBarComponent是一致的,所以不再列举
    }
    
    • IToolBoxComponent,辅助工具栏组件
    public interface IToolBoxComponent extends Component, IRoleSwitcher {
            //...省略其他Api
    }
    
    public class ToolBoxComponent extends BaseRoomComponent implements IToolBoxComponent {
            //...实现方法和BottomBarComponent是一致的,所以不再列举
    }
    
    • IRoleComponent,角色组件,中介类
    public class RoleComponent extends BaseRoomComponent implements IRoleComponent {
    @Override
        public void setNormalUserRole() {
            getComponentProvider().getBottomBarComponent().setNormalUserRole();
            getComponentProvider().getApplyForSeatComponent().setNormalUserRole();
            getComponentProvider().getToolBoxComponent().setNormalUserRole();
        }
    
        @Override
        public void setManagerRole() {
            getComponentProvider().getBottomBarComponent().setManagerRole();
            getComponentProvider().getApplyForSeatComponent().setManagerRole();
            getComponentProvider().getToolBoxComponent().setManagerRole();
        }
    
        @Override
        public void setSeatUpRole() {
            getComponentProvider().getBottomBarComponent().setSeatUpRole();
            getComponentProvider().getApplyForSeatComponent().setSeatUpRole();
            getComponentProvider().getToolBoxComponent().setSeatUpRole();
        }
    
        @Override
        public void setTeacherRole() {
            getComponentProvider().getBottomBarComponent().setTeacherRole();
            getComponentProvider().getApplyForSeatComponent().setTeacherRole();
            getComponentProvider().getToolBoxComponent().setTeacherRole();
        }
    
        @Override
        public void setVisitorRole() {
            getComponentProvider().getBottomBarComponent().setVisitorRole();
            getComponentProvider().getApplyForSeatComponent().setVisitorRole();
            getComponentProvider().getToolBoxComponent().setVisitorRole();
        }
    
        @Override
        public void setForbidSpeakRole() {
            getComponentProvider().getBottomBarComponent().setForbidSpeakRole();
            getComponentProvider().getApplyForSeatComponent().setForbidSpeakRole();
            getComponentProvider().getToolBoxComponent().setForbidSpeakRole();
        }
    }
    
    • 切换调用处调用
    mDataStore = getDataStore();
        //监听房间信息改变切换角色。
        mDataStore.getLiveRoomViewModel().getRoomInformationLiveData().observe(getLifecycleOwner(), new Observer<RoomInformationModel>() {
        @Override
        public void onChanged(@Nullable RoomInformationModel roomInformationModel) {
            if (roomInformationModel == null) {
                return;
            }
            IMRoomInfoModel roomInfoModel = roomInformationModel.getRoomInfo();
            IMSendUserModel currentUser = mDataStore.getLiveRoomViewModel().getCurrentUserLiveData().getValue();
            if (currentUser == null) {
                return;
            }
            //这里简单期间,省略了决定角色的生成,决定后通知其他组件切换样式
            IRoleComponent roleComponent = getComponentProvider().getRoleComponent();
            //老师角色
            if (currentUser.isTeacher()) {
                roleComponent.setTeacherRole();
            } else if (currentUser.isNormalUser()) {
                //普通用户角色
                roleComponent.setNormalUserRole();
            } else if (currentUser.isSeatUpUser()) {
                //上座用户角色
                roleComponent.setSeatUpRole();
            } else if (currentUser.VisitorRole()) {
                //游客角色
                roleComponent.setVisitorRole();
            } else if (currentUser.isForbidSpeakUser()) {
                //禁言用户角色
                roleComponent.setForbidSpeakRole();
            }
        }
    });
    

    总结

    • 外观模式的优点:提供统一入口方法给外部,隐藏内部子系统的细节。

    • 外观模式的缺点,外观类没有遵循开闭原则,当我们的业务变更时,可能就需要修改外观类,增加新的逻辑和子系统类。

    相关文章

      网友评论

        本文标题:设计模式实践-外观模式

        本文链接:https://www.haomeiwen.com/subject/skompktx.html