外观模式

我发现写设计模式的文章,怎么举例子是个技术活啊。。。很多东西你不实际去用真的不会真正的体会到设计模式带来的一些好处,最近公司的一个客户要做一个考勤功能,这个功能虽然是我们公司产品的标准功能,但是有些东西还是二次开发一下的。虽然很费劲的实现了大致的功能,但是代码乱的一塌糊涂,趁着周末整理了一下代码,也试着用了一下模版方法模式(计算出勤率),适配器模式(考勤接口和工资接口的对接),在我把23种设计模式学习完之后,再来说一说实际的运用把,今天聊了聊外观模式。

在上面我说了一个考勤功能,我们通过这个考勤功能分析一下外观模式,在客户的这个系统中,考勤最主要的作用就是计算工资,但是因为工资这个模块并不是我做的,所以我要放开一个接口,提供给我的同事一些数据,比如出勤率,个人扣分情况等等。这个内部实现其实还是有些复杂的。因为我要考虑他是否正常打卡,是否是周末,是否是法定假期,没有正常打卡的话是否请假,是否补卡,针对请假类型,迟到早退等等计算他所扣的分数。但是这些东西,我的同事肯定不会关心,他只要传递一个人员ID到我开放的接口上,我就把他所需数据返回回去就可以了。换句话说,为复杂的模块提供外界访问的模块,来隐藏系统的复杂性。这就是外观模式。

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

那我们通过代码来看一下吧。首先是我考勤功能的接口定义,接口有两个方法,一个是工作日的计算一个出勤天数的计算

interface Attence {
    //工作日
    void getWorkDay();

    //出勤天数
    void getRealWorkDay(int userID);

}

在我的考勤功能中,有一般员工和特殊员工,他们的工作日的计算方法是不同的,但是出勤天数这个方法计算是相同的,我们让两种员工都去实现这个出勤天数就显得繁琐了,这个时候怎么办呢?我使用抽象类解决这个问题。

abstract class AbstractAttence implements Attence {

    @Override
    public abstract void getWorkDay();

    @Override
    public void getRealWorkDay(int userID) {
        System.out.println(userID + "的人员出勤天数为XX天");
    }
}

这个抽象方法中,保留了工作日的计算,实现了出勤天数的计算,那我们就来具体实现两种员工了:

//一般工作人员打卡
class Card extends AbstractAttence {

    @Override
    public void getWorkDay() {
        System.out.println("一般员工,周一到周五打卡,工作日大约22天");
    }


}

特殊员工:

//特殊人员打卡
class CardSpecial extends AbstractAttence {

    @Override
    public void getWorkDay() {
        System.out.println("特殊员工:柜员,工作日大约为15天");
    }


}

具体的实现方法这里就隐藏了。走到这里就进入了最关键的一步了,就是外观模式的访问的接口。这个接口应该提供获取两种员工工作日,已经人员出勤天数的数据。

//外观类
class Facade {
    Attence attence = new Card();
    Attence attence1 = new CardSpecial();

    public void getData(int temp) {
        if (temp == 0) {
            attence.getWorkDay();
        } else {
            attence1.getWorkDay();
        }
    }

    public void getRealWorkDay(int userID) {
        attence.getRealWorkDay(userID);
    }
}

走到这里我想你已经知道什么是外观模式,我觉得不是特别难理解,个人来说,平时使用这种模式还是很多的,但是我并不知道这是外观模式。

看一下效果:

Connected to the target VM, address: '127.0.0.1:49917', transport: 'socket'
一般员工,周一到周五打卡,工作日大约22天
特殊员工:柜员,工作日大约为15天
12的人员出勤天数为XX天
Disconnected from the target VM, address: '127.0.0.1:49917', transport: 'socket'

Process finished with exit code 0

例子举完了,那么我们聊一下理论的东西

意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

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

优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。

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

使用场景: 1、为复杂的模块或子系统提供外界访问的模块。 2、子系统相对独立。 3、预防低水平人员带来的风险。

注意事项:在层次化结构中,可以使用外观模式定义系统中每一层的入口。

更多文章请关注公众号:每天学Java。想获得更多最新面试提醒请进入小程序:每天学Java

 公众号二维码:                                                                                          小程序二维码:

外观模式                       外观模式