设计模式(四)——生成器模式

问题提出

在类的应用中,有些简单的类是容易创建对象的,直接调用构造方法即可。例如:

Student student = new Student("1001", "张三", 20);
Circle circle = new Circle(10.0f);

而有些类却不宜直接创建对象的,成员变量是自定义类型,例如:

public class Product {
    Unit1 u1;
    Unit2 u2;
    Unit3 u3;
}

上述代码可知,Product由Unit1、Unit2、Unit3三个单位组成,不能简单地由Product product = Product(Unit1 u1, Unit2 u2, Unit3)获得,必须先生成具体的u1、u2、u3,然后才能获得Product对象。简单实现如下:

public class Product {
    Unit1 u1;
    Unit2 u2;
    Unit3 u3;

    public void createUnit1(){
        // u1=...
    }
    public void createUnit2(){
        // u2=...
    }
    public void createUnit3(){
        // u3=...
    }
    public void composite(){
        // u1+u2+u3
    }

    public static void main(String[] args) {
        Product p = new Product();
        p.createUnit1();
        p.createUnit2();
        p.createUnit3();
        p.composite();
    }
}

上述代码仅解决了一类Product对象的创建问题,如果有两类Product呢?

public class Product {
    Unit1 u1;
    Unit2 u2;
    Unit3 u3;

    // 创建第一种Product对象方法组
    public void createUnit1() {
        // u1=...
    }

    public void createUnit2() {
        // u2=...
    }

    public void createUnit3() {
        // u3=...
    }

    // 创建第二种Product对象方法组
    public void createUnit1_2() {
        // u1=...
    }

    public void createUnit2_2() {
        // u2=...
    }

    public void createUnit3_2() {
        // u3=...
    }

    public void composite(){
        // u1+u2+u3
    }

    public static void main(String[] args) {
        int type = 1;  // 创建第一种Product对象标识
        Product p = new Product();
        if (type == 1) {
            p.createUnit1();
            p.createUnit2();
            p.createUnit3();
            p.composite();
        } else if (type == 2){
            p.createUnit1_2();
            p.createUnit2_2();
            p.createUnit3_2();
            p.composite();
        }
        p.composite();
    }
}

随着Product产品种类的增多和减少,必须修改已有的源代码。

生成器模式

生成器模式也称为建造者模式。生成器模式的意图在于将一个复杂的队形的构建与其表示相分离,使得同样的建造过程可以创建不同的表示。

在软件设计中,有时候面临一个非常复杂的对象的创建工作。这个复杂的对象通常可以分成几个较小的子部分,由各个子对象组合出这个复杂的对象的过程相对来说比较稳定,但是子对象的创建过程各不相同并且可能发生变化

根据OOD中的OCP原则,应该将子对象的构建过程进行变化封装。代码如下

标准的生成器模式

产品

public class Product {
    Unit1 u1;
    Unit2 u2;
    Unit3 u3;
}

生成器类接口Build

public interface Build {
    void createUnit1();
    void createUnit2();
    void createUnit3();
    Product composite();
}

第一种生成器

public class BuildProduct1 implements Build {
    Product p = new Product();

    @Override
    public void createUnit1() {
        // p.u1 = ...
    }

    @Override
    public void createUnit2() {
        // p.u2 = ...
    }

    @Override
    public void createUnit3() {
        // p.u3 = ...
    }

    @Override
    public Product composite() {
        // ...
        return p;
    }
}

第二种生成器(若需求发生变化,只需添加或删除相应的生成器类)

public class BuildProduct2 implements Build {
    Product p = new Product();

    @Override
    public void createUnit1() {
        // p.u1 = ...
    }

    @Override
    public void createUnit2() {
        // p.u2 = ...
    }

    @Override
    public void createUnit3() {
        // p.u3 = ...
    }

    @Override
    public Product composite() {
        // ...
        return p;
    }
}

统一的调度类

public class Director {
    private Build build;

    public Director(Build build){
        this.build = build;
    }

    public Product build(){
        build.createUnit1();
        build.createUnit2();
        build.createUnit3();
        return build.composite();
    }

    public static void main(String[] args) {
        Build build = new BuildProduct1();
        Director director = new Director(build);
        Product p = director.build();
    }
}

通过上述代码,可知生成器设计模式涉及四个关键角色:

  • 产品(Product)
  • 抽象生成器(Build)
  • 具体生成器
  • 指挥类(Director)

与常规接口相比,生成器接口Build是特殊的流程控制接口,该接口中定义的方法必须依据某种顺序执行,一个都不能少。因此,在程序设计中需要体现 流程 这一特点。Director类是对 流程 的封装类,其中build()方法决定了流程的控制过程。

弱生成器模式

若Build接口中,不包含定义子过程的方法,仅包含创建方法create()。即不清楚生产的产品分为多少个子过程。

Build接口

public interface Build {
    Product create();
}

具体的生成器类

public class BuildProduct1 implements Build {

    private Product p = new Product();

    private void createUnit1(){
        // p.u1 = ...
    }

    private void createUnit2(){
        // p.u2 = ...
    }

    private void createUnit3(){
        // p.u3 = ...
    }

    public Product composite() {
        // ...
        return p;
    }

    @Override
    public Product create() {
        createUnit1();
        createUnit2();
        createUnit3();
        return composite();
    }
}

指挥者类

public class Director {
    private Build build;

    public Director(Build build){
        this.build = build;
    }

    public Product build(){
        return build.create();
    }
}

对于生成器模式来说,抽象生成器具体生成器是必不可缺的。上述代码中,Director类若不需要也可以删除。

Build接口可定义成泛型接口,不单单表示生成Product对象

public interface Build<T> {
    T create();
}

通过派生类方式实现

public abstract class Product {
    Unit1 u1;
    Unit2 u2;
    Unit3 u3;

    abstract void createUnit1();
    abstract void createUnit2();
    abstract void createUnit3();
    abstract void composite();
}
public class BuildProduct1 extends Product{
    @Override
    void createUnit1() {
        // u1 = ...
    }

    @Override
    void createUnit2() {
        // u2 = ...
    }

    @Override
    void createUnit3() {
        // u3 = ...
    }

    @Override
    void composite() {
        // 关联u1,u2,u3
    }
}
public class Director {
    Product p;

    public Director(Product p){
        this.p = p;
    }

    public void build(){
        p.createUnit1();
        p.createUnit2();
        p.createUnit3();
        p.composite();
    }
}

应用案例

数据库数据导入功能类,将不同格式的学生成绩文件导入到数据库表score中,表结构如下。

序号字段名说明关键字
1StudNO学号
2Studname姓名
3Score成绩

虽然学生成绩文件的格式不同,但导入score表中的流程是相同的,如下图

Created with Raphaël 2.2.0 开始 打开文件 文件结束否? 关闭文件 结束 获得当前一个学生记录 当前记录存入数据库 yes no

关键代码如下

public abstract class AbstractBuild {
    public abstract boolean open(String strPath);
    public abstract boolean hasNext();
    public abstract Score next();
    public abstract void close();
    public boolean saveToDb(Score s){
        String strSQL = "INSERT INTO score VALUES('"+s.getStudno()+"','"+s.getName()+"',"+s.getScore()+")";
        DbProc dbobj = new DbProc();
        try {
            dbobj.connect();
            dbobj.executeUpdate(strSQL);
            dbobj.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
}
public class Score {
    private String studno;
    private String name;
    private int score;

    public String getStudno() {
        return studno;
    }

    public void setStudno(String studno) {
        this.studno = studno;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}
public class Director {

    AbstractBuild build;

    public Director(AbstractBuild build){
        this.build = build;
    }

    public void build(String strPath){
        build.open(strPath);
        while (build.hasNext()){
            Score s = build.next();
            build.saveToDb(s);
        }
        build.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值