蜗牛君漫聊设计模式---建造者模式

本文介绍了建造者模式的概念及其核心元素,通过五险一金的缴纳场景来阐述该模式的实现步骤。首先定义了员工类及Builder抽象类,接着创建具体建造者实现类来组装员工的社保福利。通过Director类来规定组装顺序,展示了在不同情况下(如公司资金紧张)如何灵活调整福利组合。最后总结了建造者模式的优势:独立的业务实现和可变的组合方式,便于扩展和维护。

在这里插入图片描述

Hello~ 大家好,我是蜗牛君,我们又见面了。今天依然是蜗牛君漫聊设计模式系列中的文章—建造者模式。咱们举一个现实中的例子,可能没那么完全的恰当,但是基本的含义还是能够表达清楚的。作为一名职场人士,缴纳五险一金是每个职场中人的必备属性。用我们熟悉的互联网公司来举例,正规的公司会给员工缴纳标准的五险一金,实力雄厚的大厂会为员工缴纳六险一金甚至七险一金,而有的初创公司或者想法克扣员工利益的公司只给员工缴纳五险不缴纳公积金,或者上三险,最差的是五险一金一点都不给缴纳,蜗牛君刚来北京时的第一家公司(在居民楼里办公,俗称小作坊)就是这种情况,不给缴纳社保的原因是试用期不给缴纳,转正后给缴纳(这违反了劳动法)。那么建造者模式和缴纳五险一金有啥关系呢?正是因为这些不正规公司的存在,他们的这一特性才和建造者模式的核心思想搭上边。

01

建造者模式的定义

将一个复杂对象的构建与它的表示分离开,使得同样的构建过程可以创建不同的表示。

建造者模式的核心元素
  • Product产品类:基本的业务逻辑。
  • Builder抽象建造者:规范产品的组建,一般由子类实现。
  • ConcreteBuilder具体建造者:实现抽象建造者的所有方法,并返回一个组建好的产品。
  • Director导演类:负责安排已有模块的顺序,然后告诉Builder开始建造。

02

标准版建造者模式的实现
第一步,确定我们的业务类,就是员工,缴纳五险一金是每个员工的公共属性,因此我们可以创建员工抽象类,定义这些公共属性。
public abstract class Employee {
    private List<String> sequence;

    /**
     * 从工资中扣除 失业保险
     */
    protected abstract void deductUnemploymentInsurance();

    /**
     * 从工资中扣除 养老保险
     */
    protected abstract void deductEndowmentInsurance();

    /**
     * 从工资中扣除 医疗保险
     */
    protected abstract void deductHospitalizationInsurance();

    /**
     * 从工资中扣除 工伤保险
     */
    protected abstract void deductEmploymentInjuryInsurance();

    /**
     * 从工资中扣除 生育保险
     */
    protected abstract void deductMaternityInsurance();

    /**
     * 从工资中扣除 住房公积金
     */
    public abstract void deductHousingProvidentFund();

    /**
    * 设置需要缴纳的项目及其顺序
    */
    public void setSequence(List<String> sequence) {
        this.sequence = sequence;
    }

    /**
     * 执行最后的支付操作
     */
    public void payment() {
        if (sequence != null && sequence.size() != 0) {
            for (String title : sequence) {
                if ("UnemploymentInsurance".equalsIgnoreCase(title)) {
                    deductUnemploymentInsurance();
                } else if ("EndowmentInsurance".equalsIgnoreCase(title)) {
                    deductEndowmentInsurance();
                } else if ("HospitalizationInsurance".equalsIgnoreCase(title)) {
                    deductHospitalizationInsurance();
                } else if ("EmploymentInjuryInsurance".equalsIgnoreCase(title)) {
                    deductEmploymentInjuryInsurance();
                } else if ("MaternityInsurance".equalsIgnoreCase(title)) {
                    deductMaternityInsurance();
                } else if ("HousingProvidentFund".equalsIgnoreCase(title)) {
                    deductHousingProvidentFund();
                }
            }
        } else {
            System.out.println("这个公司不遵守劳动法,去告他!");
        }
    }
}
  • 第一点:我们定义了员工五险一金共六个属性,这六个业务方法会在子类中实现,也就是说这六个业务方法的定义与实现都在业务类中完成了。
  • 第二点:我们定义了具体缴纳哪些费用的方法,通过一个由外界传递进来的集合决定员工能缴纳哪些社保项目并且还能设置缴纳的顺序,而具体的业务细节在业务抽象类中实现了。
  • 总结:以上两点就是业务抽象类的具体作用,所有与业务相关的细节都在这个抽象类中定义好了并实现了部分业务逻辑。
第二步,定义我们的业务实现类,实现每个业务功能细节。
public class EmployeeA extends Employee {
    private String name;

    public EmployeeA(String name) {
        this.name = name;
    }

    @Override
    protected void deductUnemploymentInsurance() {
        // 实现业务细节
        System.out.println("姓名:" + name + ",已扣除失业保险");
    }

    @Override
    protected void deductEndowmentInsurance() {
        // 实现业务细节
        System.out.println("姓名:" + name + ",已扣除养老保险");
    }

    @Override
    protected void deductHospitalizationInsurance() {
        // 实现业务细节
        System.out.println("姓名:" + name + ",已扣除医疗保险");
    }

    @Override
    protected void deductEmploymentInjuryInsurance() {
        // 实现业务细节
        System.out.println("姓名:" + name + ",已扣除工伤保险");
    }

    @Override
    protected void deductMaternityInsurance() {
        // 实现业务细节
        System.out.println("姓名:" + name + ",已扣除生育保险");
    }

    @Override
    public void deductHousingProvidentFund() {
        // 实现业务细节
        System.out.println("姓名:" + name + ",已扣除住房公积金");
    }
}
  • 总结:关于功能业务方面的代码我们都写完了,业务类的功能就是实现业务逻辑,其实这里我们应用了另一个设计模式—模板方法模式。
第三步,创建Builder抽象类,即建造者类。在上一步中,业务相关的功能我们都做完了,下面需要根据不同的情况对业务进行组装,这就是Builder类的功能。
public abstract class Company {
    /**
     * 给员工缴纳哪些社保
     *
     * @param sequence
     */
    public abstract void setSequence(List<String> sequence);

    /**
     * 给该员工缴纳社保
     *
     * @return
     */
    public abstract Employee getEmployee();
}
第四步,创建Builder实现类。在Builder实现类中对员工的社保福利进行操。
public class CompanyA extends Company {
    private Employee employee;

    public CompanyA(String name) {
        // 关键点一
        employee = new EmployeeA(name);
    }
    
    @Override
    public void setSequence(List<String> sequence) {
        // 关键点二
        employee.setSequence(sequence);
    }
    
    @Override
    public Employee getEmployee() {
        // 关键点三
        return employee;
    }
}
  • 关键点一解读:创建一个需要缴纳社保的员工;
  • 关键点二解读:设置这个员工享受的社保福利项目;
  • 关键点三解读:获取这名享受社保福利的员工对象;
第五步,终于到了发工资的时候,发工资前要扣除五险一金所占去的金额并进行缴纳。
public class Client {
    public static void main(String[] args) {
        // A公司的员工---蜗牛君
        Company company = new CompanyA("蜗牛君");
        
        List<String> sequence = new ArrayList<>();
        // 给蜗牛君缴纳 失业保险
        sequence.add("UnemploymentInsurance");
        // 给蜗牛君缴纳 养老保险
       sequence.add("EndowmentInsurance");
       // 给蜗牛君缴纳 医疗保险
       sequence.add("HospitalizationInsurance");
       // 给蜗牛君缴纳 工伤保险
       sequence.add("EmploymentInjuryInsurance");
       // 给蜗牛君缴纳 生育保险
       sequence.add("MaternityInsurance");
       // 给蜗牛君缴纳 住房公积金
       sequence.add("HousingProvidentFund");
       company.setSequence(sequence);
       
       // 获取蜗牛君实体类
       Employee employeeA = company.getEmployee();
       // 进行缴纳
       employeeA.payment();
    }
}
Log日志
姓名:蜗牛君,已扣除失业保险
姓名:蜗牛君,已扣除养老保险
姓名:蜗牛君,已扣除医疗保险
姓名:蜗牛君,已扣除工伤保险
姓名:蜗牛君,已扣除生育保险
姓名:蜗牛君,已扣除住房公积金
  • 总结:五险一金按时缴纳了,工资也到手了,一个月的辛苦有了回报,心里美滋滋的。这家公司在员工福利方面还是很正规的。

03

坑人情况一

由于公司经营不善,资金链出现了断裂,员工的福利无法按时足额的缴纳,公司表示先给上五险,公积金后面有钱了再给补,让我们看看程序如何表示:

public class Client {
    public static void main(String[] args) {
        // A公司的员工---蜗牛君
        Company company = new CompanyA("蜗牛君");
        
        List<String> sequence = new ArrayList<>();
        // 给蜗牛君缴纳 失业保险
        sequence.add("UnemploymentInsurance");
        // 给蜗牛君缴纳 养老保险
       sequence.add("EndowmentInsurance");
       // 给蜗牛君缴纳 医疗保险
       sequence.add("HospitalizationInsurance");
       // 给蜗牛君缴纳 工伤保险
       sequence.add("EmploymentInjuryInsurance");
       // 给蜗牛君缴纳 生育保险
       sequence.add("MaternityInsurance");
       // 给蜗牛君缴纳 住房公积金
       // sequence.add("HousingProvidentFund");
       company.setSequence(sequence);
       
       // 获取蜗牛君实体类
       Employee employeeA = company.getEmployee();
       // 进行缴纳
       employeeA.payment();
    }
}
Log日志
姓名:蜗牛君,已扣除失业保险
姓名:蜗牛君,已扣除养老保险
姓名:蜗牛君,已扣除医疗保险
姓名:蜗牛君,已扣除工伤保险
姓名:蜗牛君,已扣除生育保险
  • 总结:我们直接将公积金这一项删除就能拼装出新的福利模型。
坑人情况二

公司没钱了,员工福利五险一金改为三险(因为三险是劳动法规定必须缴纳的)并且先给缴纳失业保险,再给缴纳医疗保险,最后缴纳养老保险,为什么是这个顺序?因为养老保险钱最多,当然实际情况中是不能这样缴纳的,这里是为了体现建造者模式的特点:顺序性。

public class Client {
    public static void main(String[] args) {
        // A公司的员工---蜗牛君
        Company company = new CompanyA("蜗牛君");
        
        List<String> sequence = new ArrayList<>();
        // 给蜗牛君缴纳 失业保险
        sequence.add("UnemploymentInsurance");
        // 给蜗牛君缴纳 医疗保险
       sequence.add("HospitalizationInsurance");
       // 给蜗牛君缴纳 养老保险
       sequence.add("EndowmentInsurance");
       // 给蜗牛君缴纳 工伤保险
       // sequence.add("EmploymentInjuryInsurance");
       // 给蜗牛君缴纳 生育保险
       // sequence.add("MaternityInsurance");
       // 给蜗牛君缴纳 住房公积金
       // sequence.add("HousingProvidentFund");
       company.setSequence(sequence);
       
       // 获取蜗牛君实体类
       Employee employeeA = company.getEmployee();
       // 进行缴纳
       employeeA.payment();
    }
}
Log日志
姓名:蜗牛君,已扣除失业保险
姓名:蜗牛君,已扣除医疗保险
姓名:蜗牛君,已扣除养老保险
总结

通过以上三种情况,充分体现出了建造者模式的优势:灵活。因为在业务类中功能相关的点都完成了并且每个业务点是独立的,这就相当于一些零件。而建造者类中可以根据具体情况任意的调用业务类中的零件进行组合拼装,最后输出一个成品。用一句话描述就是,在业务功能点完成的情况下,通过对业务点任意的拼装最后输出不同的产品。

04

进一步完善建造者模式

蜗牛君所在的公司是一个集团公司下面的子公司,而这家集团公司下面有多家子公司,每个子公司的社保缴纳项目是固定的,因此我们可以在封装一层集团公司,即Director。

我们在创建一个子公司B
public class CompanyB extends Company {
    private Employee employee;

    public CompanyB(String name) {
        employee = new EmployeeB(name);
    }

    @Override
    public void setSequence(List<String> sequence) {
        employee.setSequence(sequence);
    }

    @Override
    public Employee getEmployee() {
        return employee;
    }
}
定义一个Director类,这个类用来规定已有模块的顺序
public class Director {
    private List<String> sequence = new ArrayList<>();
    // 蜗牛君所在公司
    private Company companyA = new CompanyA("蜗牛君");
    // 蜗牛君的弟弟所在公司
    private Company companyB = new CompanyB("蜗牛君的弟弟");

    // 蜗牛君所在公司的缴费项目及顺序:全额缴纳五险一金
    public Employee getCompanyAEmployee() {
        sequence.clear();
        sequence.add("UnemploymentInsurance");
        sequence.add("EndowmentInsurance");
        sequence.add("HospitalizationInsurance");
        sequence.add("EmploymentInjuryInsurance");
        sequence.add("MaternityInsurance");
        sequence.add("HousingProvidentFund");
        companyA.setSequence(sequence);
        return companyA.getEmployee();
    }

    // 蜗牛君的弟弟所在公司的缴费项目及顺序:只缴纳三险一金
    public Employee getCompanyBEmployee() {
        sequence.clear();
        sequence.add("MaternityInsurance");
        sequence.add("EndowmentInsurance");
        sequence.add("HospitalizationInsurance");
        sequence.add("HousingProvidentFund");
        companyB.setSequence(sequence);
        return companyB.getEmployee();
    }
}
终于又到了发工资的时候了,先缴纳社保吧
public class Client {
    public static void main(String[] args) {
        // 创建集团公司
        Director director = new Director();
        // 给蜗牛君缴纳五险一金
        Employee employeeA = director.getCompanyAEmployee();
        employeeA.payment();
        // 给蜗牛君的弟弟缴纳三险一金
        Employee employeeB = director.getCompanyBEmployee();
       employeeB.payment();
    }
}
Log日志
姓名:蜗牛君,已扣除失业保险
姓名:蜗牛君,已扣除养老保险
姓名:蜗牛君,已扣除医疗保险
姓名:蜗牛君,已扣除工伤保险
姓名:蜗牛君,已扣除生育保险
姓名:蜗牛君,已扣除住房公积金

姓名:蜗牛君的弟弟,已扣除失业保险
姓名:蜗牛君的弟弟,已扣除养老保险
姓名:蜗牛君的弟弟,已扣除医疗保险
姓名:蜗牛君的弟弟,已扣除住房公积金

05

总结

不知道大家通过上面的现实例子有没有体会到建造者模式的核心思想,在这里我给大家再次简单的总结一下

第一点:所有业务功能都在业务类中完成并且独立,其他的类中都没有涉及业务实现相关的代码,这些业务点可比作零件。

第二点:Builder类对已有业务点进行拼装,虽然业务点的实现逻辑一样,但是通过组装时不同的顺序不同的选项最后输出不同的产品。而且各个拼装类又相互独立,易于扩展。

第三点:建造者模式的核心要义是:拼装时,顺序不同,零件不同,最后输出不同的产品。


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值