研磨设计模式day08生成器模式

目录

场景

代码示例

有何问题 

解决方案

定义​编辑

 生成器结构图

解决思路

模式讲解

生成器模式的优点

思考

何时选用


场景

针对学习工厂方法模式时,提到了导出数据的框架。

我们当时使用创建器(抽象类)里面提供的抽象方法(返回值为接口也就是Product),通过继承这个抽象类区分不同的导出数据方法。最后在客户端调用具体的创建器实现来完成。

现在我们需要在导出的内容和格式上做出要求。

代码示例

描述文件头的对象

package day07生成器模式;

/**
 * 文件头
 */
public class ExportHeaderModel {
    /**
     * 编号
     */
    private String depId;
    /**
     * 导出日期
     */
    private String exportDate;

    public String getDepId() {
        return depId;
    }

    public void setDepId(String depId) {
        this.depId = depId;
    }

    public String getExportDate() {
        return exportDate;
    }

    public void setExportDate(String exportDate) {
        this.exportDate = exportDate;
    }
}

描述文件内容的

package day07生成器模式;

/**
 * 描述输出数据的对象
 */
public class ExportDataModel {
    /**
     * 产品编号
     */
    private String productId;
    /**
     * 销售价格
     */
    private double price;
    /**
     * 销售数量
     */
    private double amount;

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }
}

描述文件尾的

package day07生成器模式;

/**
 * 输出到文件尾的内容
 */
public class ExportFooterModel {
    /**
     * 输出人
     */
    private String exportUser;

    public String getExportUser() {
        return exportUser;
    }

    public void setExportUser(String exportUser) {
        this.exportUser = exportUser;
    }
}

具体的导出实现,导出到txt

package day07生成器模式;

import java.util.Collection;
import java.util.Map;

/**
 * 具体的导出实现
 * 导出数据到文本文件的对象
 */
public class ExportToTxt {

    public void export(ExportHeaderModel ehm, Map<String, Collection<ExportDataModel>> mapData,ExportFooterModel efm){

        StringBuffer buffer = new StringBuffer();
        // 1. 拼接文件头
        buffer.append(ehm.getDepId() + "," + ehm.getExportDate() + "\n");
        // 2. 拼接文件体内容
        for (String s : mapData.keySet()) {
            // 先拼接表名称
            buffer.append(s + "\n");
            // 再循环拼接具体数据
            for (ExportDataModel edm : mapData.get(s)) {
                buffer.append(edm.getProductId() + "," + edm.getPrice() + "," + edm.getAmount() + "\n");
            }
        }
        // 3. 拼接文件尾
        buffer.append(efm.getExportUser());
        System.out.println("输出到文本文件的内容: \n" + buffer);
    }
}

导出到xml

package day07生成器模式;

import java.util.Collection;
import java.util.Map;

/**
 * 具体的导出实现
 * 导出数据到xml文件的对象
 */
public class ExportToXml {

    public void export(ExportHeaderModel ehm, Map<String, Collection<ExportDataModel>> mapData,ExportFooterModel efm){

        StringBuffer buffer = new StringBuffer();
        // 1. 拼接文件头
        buffer.append("<?xml version = '1.0' encoding='gb2312'?>\n");
        buffer.append("<Report>\n");
        buffer.append("     <Header>\n");
        buffer.append("         <DepId>" + ehm.getDepId() + "</DepId>\n");
        buffer.append("         <ExportDate>" + ehm.getExportDate() + "</ExportDate>\n");
        buffer.append("     </Header>\n");
        // 2. 拼接文件体内容
        buffer.append("<Body>\n");
        for (String s : mapData.keySet()) {
            // 先拼接表名称
            buffer.append(" <Datas TableName=\"" + s + "\">\n");
            // 然后驯悍拼接具体数据
            for (ExportDataModel edm : mapData.get(s)) {
                buffer.append("     <Data>\n");
                buffer.append("         <ProductId>\n" + edm.getProductId() + "</ProductId>\n");
                buffer.append("         <Price>\n" + edm.getPrice() + "</Price>\n");
                buffer.append("         <Amount>\n" + edm.getAmount() + "</Amount>\n");
                buffer.append("     </Data>\n");
            }
            buffer.append("     </Datas>\n");
        }
        buffer.append("</Body>\n");
        // 3. 拼接文件尾
        buffer.append(" <Footer>\n");
        buffer.append("     <ExportUser>" + efm.getExportUser() + "</ExportUser>\n");
        buffer.append(" </Footer>\n");
        buffer.append(" </Report>\n");
        System.out.println("输出到文本文件的内容: \n" + buffer);
    }
}

客户端

package day07生成器模式;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

public class Client {
    public static void main(String[] args) {
        // 准备测试数据
        ExportHeaderModel ehm = new ExportHeaderModel();
        ehm.setExportDate("2023-08-19");
        ehm.setDepId("一分公司");

        HashMap<String, Collection<ExportDataModel>> mapData = new HashMap<>();
        ArrayList<ExportDataModel> col = new ArrayList<>();
        ExportDataModel edm1 = new ExportDataModel();
        edm1.setProductId("产品001号");
        edm1.setPrice(100);
        edm1.setAmount(80);

        ExportDataModel edm2 = new ExportDataModel();
        edm2.setProductId("产品002号");
        edm2.setPrice(99);
        edm2.setAmount(55);

        col.add(edm1);
        col.add(edm2);

        mapData.put("销售记录表", col);

        ExportFooterModel efm = new ExportFooterModel();
        efm.setExportUser("张三");

        ExportToTxt toTxt = new ExportToTxt();
        toTxt.export(ehm , mapData , efm);

        ExportToXml exportToXml = new ExportToXml();
        exportToXml.export(ehm , mapData , efm);


    }
}

有何问题 

发现不管是输出到txt还是xml都有共同的步骤,拼接头,拼接数据,拼接尾,最后输出成为文件。

处理步骤是一样的,具体实现不一样,因此将处理步骤应该提炼出来,形成公共的处理过程。易复用。

解决方案

生成器模式

定义
 生成器结构图

解决思路

将构建过独立出来,当作指导者,由它来指导装配过程,但是不负责每一步具体的实现。

光有指导者是不够的,必须要有能具体实现每步的对象,这些实现对象称作生成器。

使用实例:

三个数据模型对象不动(头,数据,尾应该展示的东西)

Build接口:生成器接口,定义创建一个输出文件对象所需的各个部件的操作

package day07生成器模式.实例;

import day07生成器模式.ExportDataModel;
import day07生成器模式.ExportFooterModel;
import day07生成器模式.ExportHeaderModel;

import java.util.Collection;
import java.util.Map;

/**
 * 生成器接口,定义创建一个输出文件对象所需的各个部件的操作
 */
public interface Builder {
    /**
     * 构建输出文件的Header部分
     * @param ehm
     */
    public void buildHeader(ExportHeaderModel ehm);

    /**
     * 构建输出文件的Data部分
     * @param mapData
     */
    public void buildBody(Map<String, Collection<ExportDataModel>> mapData);

    /**
     * 构建输出文件的Footer部分
     * @param efm
     */
    public void buildFooter(ExportFooterModel efm);
}

具体的生成器实现TxtBuild,对Build进行实现

package day07生成器模式.实例;

import day07生成器模式.ExportDataModel;
import day07生成器模式.ExportFooterModel;
import day07生成器模式.ExportHeaderModel;

import java.util.Collection;
import java.util.Map;

/**
 * 具体的生成器实现
 * 导出数据到文本文件
 */
public class TxtBuilder implements Builder{

    /**
     * 用来记录构建的文件的内容,相当于产品
     */
    private StringBuffer buffer = new StringBuffer();


    @Override
    public void buildHeader(ExportHeaderModel ehm) {
        buffer.append(ehm.getDepId() + "," + ehm.getExportDate() + "\n");
    }

    @Override
    public void buildBody(Map<String, Collection<ExportDataModel>> mapData) {
        for (String s : mapData.keySet()) {
            // 先拼接表名
            buffer.append(s + "\n");
            // 循环拼接具体数据
            for (ExportDataModel edm : mapData.get(s)) {
                buffer.append(edm.getProductId() + "," + edm.getPrice() + "," + edm.getAmount() + "\n");
            }
        }
    }

    @Override
    public void buildFooter(ExportFooterModel efm) {
        buffer.append(efm.getExportUser());
    }

    public StringBuffer getResult(){
        return buffer;
    }
}

XmlBuild实现

package day07生成器模式.实例;

import day07生成器模式.ExportDataModel;
import day07生成器模式.ExportFooterModel;
import day07生成器模式.ExportHeaderModel;

import java.util.Collection;
import java.util.Map;

public class XmlBuilder implements Builder{

    /**
     * 用来记录构建的文件的内容,相当于产品
     */
    private StringBuffer buffer = new StringBuffer();

    @Override
    public void buildHeader(ExportHeaderModel ehm) {
        buffer.append("<?xml version = '1.0' encoding='gb2312'?>\n");
        buffer.append("<Report>\n");
        buffer.append("     <Header>\n");
        buffer.append("         <DepId>" + ehm.getDepId() + "</DepId>\n");
        buffer.append("         <ExportDate>" + ehm.getExportDate() + "</ExportDate>\n");
        buffer.append("     </Header>\n");
    }

    @Override
    public void buildBody(Map<String, Collection<ExportDataModel>> mapData) {
        buffer.append("<Body>\n");
        for (String s : mapData.keySet()) {
            // 先拼接表名称
            buffer.append(" <Datas TableName=\"" + s + "\">\n");
            // 然后驯悍拼接具体数据
            for (ExportDataModel edm : mapData.get(s)) {
                buffer.append("     <Data>\n");
                buffer.append("         <ProductId>\n" + edm.getProductId() + "</ProductId>\n");
                buffer.append("         <Price>\n" + edm.getPrice() + "</Price>\n");
                buffer.append("         <Amount>\n" + edm.getAmount() + "</Amount>\n");
                buffer.append("     </Data>\n");
            }
            buffer.append("     </Datas>\n");
        }
        buffer.append("</Body>\n");
    }

    @Override
    public void buildFooter(ExportFooterModel efm) {
        buffer.append(" <Footer>\n");
        buffer.append("     <ExportUser>" + efm.getExportUser() + "</ExportUser>\n");
        buffer.append(" </Footer>\n");
        buffer.append(" </Report>\n");
    }

    public StringBuffer getResult(){
        return buffer;
    }
}

解释:这两个实现都是对Build中头、数据、尾方法的实现,只不过之前是写一起了,现在进行拆分,并提供一个返回整体对象的方法getResult()

生成器有了,现在创建一个指导者

package day07生成器模式.实例;

import day07生成器模式.ExportDataModel;
import day07生成器模式.ExportFooterModel;
import day07生成器模式.ExportHeaderModel;

import java.util.Collection;
import java.util.Map;

/**
 * 指导者,指导生成器实现进行具体的产品构建
 */
public class Director {
    /**
     * 持有当前需要使用的生成器对象
     */
    private Builder builder;

    /**
     * 构造方法
     * @param builder 生成器对象
     */
    public Director(Builder builder){
        this.builder = builder;
    }

    public void construct(ExportHeaderModel ehm, Map<String, Collection<ExportDataModel>> mapData, ExportFooterModel efm){
        //1. 先构建Header
        builder.buildHeader(ehm);
        //2. 然后构建Body
        builder.buildBody(mapData);
        //3. 再构建Footer
        builder.buildFooter(efm);
    }
}

解释:

1.指导者顾名思义要指导什么东西,那么得有这个东西吧,所以持有这个Build接口,并且在创建的时候接入这个build。

2.怎么指导呢?指导方法construct

Client客户端测试

package day07生成器模式.实例;

import day07生成器模式.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

public class Client {
    public static void main(String[] args) {
        // 准备测试数据
        ExportHeaderModel ehm = new ExportHeaderModel();
        ehm.setExportDate("2023-08-19");
        ehm.setDepId("一分公司");

        HashMap<String, Collection<ExportDataModel>> mapData = new HashMap<>();
        ArrayList<ExportDataModel> col = new ArrayList<>();
        ExportDataModel edm1 = new ExportDataModel();
        edm1.setProductId("产品001号");
        edm1.setPrice(100);
        edm1.setAmount(80);

        ExportDataModel edm2 = new ExportDataModel();
        edm2.setProductId("产品002号");
        edm2.setPrice(99);
        edm2.setAmount(55);

        col.add(edm1);
        col.add(edm2);

        mapData.put("销售记录表", col);

        ExportFooterModel efm = new ExportFooterModel();
        efm.setExportUser("张三");

//        ExportToTxt toTxt = new ExportToTxt();
//        toTxt.export(ehm , mapData , efm);
//
//        ExportToXml exportToXml = new ExportToXml();
//        exportToXml.export(ehm , mapData , efm);
        
        // 测试输出到文本文件
        TxtBuilder txtBuilder = new TxtBuilder();
        // 创建指导者
        Director director = new Director(txtBuilder);
        director.construct(ehm,mapData,efm);
        System.out.println("输出到文本文件: \n"+txtBuilder.getResult());
        
        System.out.println("===========================");

        // 测试输出到Xml文件
        XmlBuilder xmlBuilder = new XmlBuilder();
        // 创建指导者
        Director director1 = new Director(xmlBuilder);
        director1.construct(ehm,mapData,efm);
        System.out.println("输出到xml文件 \n"+xmlBuilder.getResult());

    }
}

解释:更改了之前具体得创建方法,现在先用build实现类定义我要输出成什么格式,实现类写完后得有人指导实现类进行构建啊,那我就创建一个Director,入参传入实现类并调用构建方法构建。

具体的构建还是通过build的实现来构建的,它怎么知道是谁呢?因为我们在构造方法中传入了build,那么传入的是Txt那就是Txt构建,传入的是Xml,那就用xml构建

模式讲解

生成器模式的重心在于分离构建算法和具体的构造方法。我的指导者只是把Buildj接口拿过来,内部提供构建的方法也是针对接口中方法的顺序进行一步一步搭建,但是这些方法的具体实现是在他们各自的Build实现类里面(TxtBuilder/XmlBuilder)。

生成器模式的优点

思考

生成器的本质:分离整体构建算法和部件构造

何时选用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值