建造者模式

建造者模式是在Android中很常见的一种设计模式,比如系统自带的AlertDialog就是以建造者模式供我们使用的,如下:

AlertDialog dialog = new AlertDialog.Builder(context)
                .setIcon(R.drawable.icon)
                .setTitle("title")
                .setMessage("message")
                .setPositiveButton("positive", (dialog1, which) -> {
                    
                }).setNegativeButton("negative", (dialog12, which) -> {
                    
                })
                .create();
        dialog.show();

对于AlertDialog这个复杂的对象,使用建造者模式可以让对象创建的过程分步进行,传参清晰明了,选择性的传入需要的参数来创建所需的对象,而不必关心内部的实现过程,也不必像构造普通对象那样必须在构造方法中传入所有参数,或者有太多的set()方法,不知道调用哪个。

以上的建造者写法实际上是一个简化版,标准的建造者模式应有以下几种角色:

1.Product——抽象产品类;

2.Builder——抽象建造者类,定义基本的建造方法,对于不同的产品,需要继承建造者类,实现具体的建造方法;

3.Director——规范抽象建造者的建造过程。

以组装电脑为例,假设组装电脑至少需要CPU、GPU、内存和系统,定义抽象电脑类:

public abstract class BaseComputer {

   protected String cpu;
   protected String gpu;
   protected int ram;
   protected String os;

   protected BaseComputer() {
   }

   public void setCpu(String cpu) {
       this.cpu = cpu;
   }

   public void setGpu(String gpu) {
       this.gpu = gpu;
   }

   public void setRam(int ram) {
       this.ram = ram;
   }

   public abstract void setOS(String os);

   @Override 
   public String toString() { 
    return "Computer:" + " cpu: " + cpu + " gpu: " + gpu + " ram: " + ram; 
   }
}

定义抽象建造者类:

public abstract class BaseComputerBuilder {

    public abstract void ofCpu(String cpu);

    public abstract void ofGpu(String gpu);

    public abstract void ofRam(int ram);

    public abstract void ofOS();

    public abstract BaseComputer create();
}

实现抽象电脑类:

public class Mac extends BaseComputer {

    @Override
    public void setOS() {
        os = "Mac OS";
    }
}

实现抽象建造者类:

public class MacBuilder extends BaseComputerBuilder {

    private Mac mac = new Mac();

    @Override
    public void ofCpu(String cpu) {
        mac.setCpu(cpu);
    }

    @Override
    public void ofGpu(String gpu) {
        mac.setGpu(gpu);
    }

    @Override
    public void ofRam(int ram) {
        mac.setRam(ram);
    }

    @Override
    public void ofOS() {
        mac.setOS();
    }

    @Override
    public BaseComputer create() {
        return mac;
    }
}

最后用Director角色来规范建造方法的调用:

public class Director {

    private BaseComputerBuilder builder;

    public Director(BaseComputerBuilder builder) {
        this.builder = builder;
    }

    public void construct(String cpu, String gpu, int ram) {
     //对象的建造过程 builder.ofCpu(cpu); builder.ofGpu(gpu); builder.ofRam(ram); builder.ofOS(); } }

使用时需要创建建造者和Director对象,传入相应的参数,而不需要关心建造的过程:

public static void main(String[] args) {
        BaseComputerBuilder builder = new MacBuilder();
        Director director = new Director(builder);
        director.construct("cpu", "gpu", 8);
        System.out.println("Computer: " + builder.create().toString());
    }

类似于系统的AlertDialog对象,我们常常为了简化结构而去掉Director角色,在Builder的建造方法中返回自己,通过链式调用的形式组装对象。修改抽象建造者和具体实现:

public abstract class BaseComputerBuilder {

    public abstract BaseComputerBuilder ofCpu(String cpu);

    public abstract BaseComputerBuilder ofGpu(String gpu);

    public abstract BaseComputerBuilder ofRam(int ram);

    public abstract BaseComputerBuilder ofOS();

    public abstract BaseComputer create();
}
public class MacBuilder extends BaseComputerBuilder {
    
    private Mac mac = new Mac();
    
    @Override
    public BaseComputerBuilder ofCpu(String cpu) {
        mac.setCpu(cpu);
        return this;
    }

    @Override
    public BaseComputerBuilder ofGpu(String gpu) {
        mac.setGpu(gpu);
        return this;
    }

    @Override
    public BaseComputerBuilder ofRam(int ram) {
        mac.setRam(ram);
        return this;
    }

    @Override
    public BaseComputerBuilder ofOS() {
        mac.setOS();
        return this;
    }

    @Override
    public BaseComputer create() {
        return mac;
    }
}

使用时更加简洁,这适用于建造方法较少或过程简单,不需要统一管理的情况:

new MacBuilder().ofCpu("cpu")
                .ofGpu("gpu")
                .ofRam(8)
                .ofOS()
                .create();

以上的建造者模式写法在大多数情况下已经够用了,但是为了对所有同类的产品的建造进行约束,限制只能用规定的建造方法来获取对象,我们可以将抽象建造者写在抽象产品内部,作为产品的内部类,并使用范型来约束建造方法的返回值:

public abstract class BaseComputer {

    protected String cpu;
    protected String gpu;
    protected int ram;

    protected BaseComputer(BaseComputerBuilder builder) {
        this.cpu = builder.cpu;
        this.gpu = builder.gpu;
        this.ram = builder.ram;
    }

    @NonNull
    @Override
    public String toString() {
        return "Computer:" +
                " cpu: " + cpu +
                " gpu: " + gpu +
                " ram: " + ram;
    }

    public abstract static class BaseComputerBuilder<T extends BaseComputerBuilder<T, K>, K extends BaseComputer> {

        private String cpu = "default cpu";
        private String gpu = "default gpu";
        private int ram = 1;

        public T ofCpu(String cpu) {
            this.cpu = cpu;
            return (T)this;
        }

        public T ofGpu(String gpu) {
            this.gpu = gpu;
            return (T)this;
        }

        public T ofRam(int ram) {
            this.ram = ram;
            return (T)this;
        }

        public abstract K build();
    }
}

这样同类型的产品在继承时,就可以有同类型的建造者,并且可以根据不同产品的需要,扩展更多的字段和建造方法,而又具备基本的建造方法:

public class AppleMac extends BaseComputer {

    //扩展的字段
    private String os;

    private AppleMac(AppleMacBuilder builder) {
        super(builder);
        this.os = builder.os;
    }

    public String getOS() {
        return os;
    }

    public static class AppleMacBuilder extends BaseComputerBuilder<AppleMacBuilder, AppleMac> {

        private String os = "default system";

        public AppleMacBuilder ofOS(String os) {
            this.os = os;
            return this;
        }

        @Override
        public AppleMac build() {
            return new AppleMac(this);
        }
    }
}

另外,我们在建造者中给字段设置了默认值,所以在创建时可以只传入需要自定义的字段:

public static void main(String[] args) {
        AppleMac appleMac = new AppleMac.AppleMacBuilder()
                .ofCpu("cpu")
                .ofOS("Mac OS")
                .build();
        System.out.println(appleMac.toString());
    }

综上,建造者模式很好的封装了复杂对象的创建过程,避免有太多的set()方法。对象创建时可以根据不同的传参和调用顺序产生不同的结果,对象的创建过程得到了统一管理,接口更加清晰,简洁易懂。并且抽象的建造者对于不同的产品建造也有更好的可扩展性。至于Director角色,如果建造过程不固定,不同产品有不同的实现,可以省略这个角色,直接在建造者中管理各自的建造过程。

 

posted @ 2021-03-14 12:15  wanghan5950  阅读(117)  评论(0)    收藏  举报