• Java设计模式之建造者模式


    概论

     什么是建造者模式呢?将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    建造者模式示例

    我们先来回忆一下在模板模式中的 示例,[内外部系统交互]中的四个步骤:

    第一步:参数校验

    第二步:封装对外的请求参数

    第三步:对外提交请求

    第四步:后置处理,例如记录操作日志

    最后核心的算法设计在run方法中。如下代码所示:

     1 public void run (ExampleContext context) {
     2 
     3         validate(context);
     4 
     5         prepare(context);
     6 
     7         proccess(context);
     8 
     9         after(context);
    10     }

    客户端只要取调用run方法就可以。一切看来都很美好,但是如果我们想要把第一步和第二步交换执行顺序。或者把第二步舍弃。或者第三步和第四步交换执行顺序等等。

    简单的描述一下问题:我们想要在一个算法中若干个步骤,客户端需要自定义步骤的顺序以及确定是否采用或者舍弃一些步骤。

    此时需要用到建造者模式。首先我们需要有抽象产品类:

     1 public abstract class AbstractProccessor {
     2 
     3     private List<String> sequence = new ArrayList<String>();
     4 
     5 
     6 
     7     public boolean validate(ExampleContext context) {
     8         if (context == null) {
     9             return false;
    10         }
    11 
    12         return true;
    13     }
    14 
    15     public abstract void prepare(ExampleContext context);
    16 
    17     public abstract void proccess(ExampleContext context);
    18 
    19     public abstract void after(ExampleContext context);
    20 
    21     protected boolean needAfterProccessing () {
    22         return true;
    23     }
    24 
    25 
    26     public List<String> getSequence() {
    27         return sequence;
    28     }
    29 
    30     public void setSequence(List<String> sequence) {
    31         this.sequence = sequence;
    32     }
    33 
    34     public void run (ExampleContext context) {
    35 
    36         for(String methodName : sequence) {
    37             if(StringUtils.isEmpty(methodName)) {
    38                 continue;
    39             }
    40 
    41             Method method = null;
    42 
    43             try {
    44                  method = this.getClass().getMethod(methodName, ExampleContext.class);
    45             } catch (Exception e) {
    46 
    47             }
    48 
    49             if(method == null) {
    50                 continue;
    51             }
    52 
    53             try {
    54                 method.invoke(this, context);
    55             } catch (Exception e) {
    56 
    57             }
    58 
    59 
    60         }
    61     }
    62 
    63 }

    第3行:声明一个表示顺序的集合,集合中存储的是算法中每个步骤的方法名。类型为String类型。

    第31行-61行:run方法通过遍历顺序集合的方式依次执行。通过反射的方式来调用。

    接下来,和模板方法中的两个具体产品类完全一样,一个是HttpProccessor,另外一个是OtherProccessor。代码如下所示:

     1 public class HttpProccessor extends AbstractProccessor {
     2 
     3     protected boolean needAfterProccessing = false;
     4 
     5     @Override
     6     public void prepare(ExampleContext context) {
     7 
     8         System.out.println("http 前置处理");
     9 
    10     }
    11 
    12     @Override
    13     public void proccess(ExampleContext context) {
    14 
    15         System.out.println("http 提交请求");
    16 
    17     }
    18 
    19     @Override
    20     public void after(ExampleContext context) {
    21 
    22         System.out.println("http 后置处理");
    23 
    24     }
    25     
    26 }
     1 public class OtherProccessor extends AbstractProccessor {
     2 
     3     @Override
     4     public void prepare(ExampleContext context) {
     5 
     6         System.out.println("other 前置处理");
     7 
     8     }
     9 
    10     @Override
    11     public void proccess(ExampleContext context) {
    12 
    13         System.out.println("other 提交请求");
    14 
    15     }
    16 
    17     @Override
    18     public void after(ExampleContext context) {
    19 
    20         System.out.println("other 后置处理");
    21 
    22     }
    23 }

    最后我们需要修改一下我们的场景类Client:

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4 
     5         AbstractProccessor proccessor = new HttpProccessor();
     6 
     7         List<String> list = new ArrayList<String>();
     8         list.add("prepare");
     9         list.add("proccess");
    10         proccessor.setSequence(list);
    11 
    12         proccessor.run(new ExampleContext());
    13 
    14 
    15     }
    16 }

    第7行-10行:设置要执行的步骤以及顺序。

    运行结果如下所示:

    http 前置处理
    http 提交请求

     当我们需要很多种场景,是不是需要去写很多种负责的场景类?在建造者设计模式中引入一个很重要的角色--建造者。场景类需要什么顺序,只需要告诉建造者就行。

    我们新增一个建造者抽象类AbtractorBuilder。

    1 public abstract class AbstractBuilder {
    2 
    3     public abstract void setSequence(List<String> list);
    4 
    5     public abstract AbstractProccessor  getProccessor();
    6 }

    再新增一个HttpBuilder和OtherBuilder

    public class HttpBuilder extends AbstractBuilder {
    
        private AbstractProccessor proccessor = new HttpProccessor();
    
        @Override
        public void setSequence(List<String> list) {
            proccessor.setSequence(list);
        }
    
        @Override
        public AbstractProccessor getProccessor() {
            return proccessor;
        }
    
    
    }
    public class OtherBuilder extends AbstractBuilder {
    
        private AbstractProccessor proccessor = new OtherProccessor();
    
        @Override
        public void setSequence(List<String> list) {
              proccessor.setSequence(list);
        }
    
        @Override
        public AbstractProccessor getProccessor() {
            return proccessor;
        }
    
    
    }

    继续修改一下场景类:

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4 
     5         List<String> list = new ArrayList<String>();
     6         list.add("prepare");
     7         list.add("proccess");
     8 
     9         HttpBuilder httpBuilder = new HttpBuilder();
    10         httpBuilder.setSequence(list);
    11 
    12         AbstractProccessor proccessor = httpBuilder.getProccessor();
    13         proccessor.run(new ExampleContext());
    14 
    15     }
    16 }

    但是我们的HttpBuilder还是在场景类中调用时,顺序还是不够灵活。 这时需要产生一个导演类,将所有预知的情况 组合的情况一一列出来。如下代码所示:

     1 public class Director {
     2 
     3     private List<String> sequence = new ArrayList<String>();
     4     private AbstractBuilder httpBuilder = new HttpBuilder();
     5     private AbstractBuilder otherBuilder = new OtherBuilder();
     6 
     7     public AbstractProccessor getHttpProccessorFirst() {
     8 
     9         this.sequence.clear();
    10         sequence.add("prepare");
    11 
    12         httpBuilder.setSequence(sequence);
    13 
    14         AbstractProccessor proccessor = httpBuilder.getProccessor();
    15 
    16         return proccessor;
    17     }
    18 
    19     public AbstractProccessor getHttpProccessorSecond() {
    20 
    21         this.sequence.clear();
    22         sequence.add("prepare");
    23         sequence.add("after");
    24 
    25         httpBuilder.setSequence(sequence);
    26 
    27         AbstractProccessor proccessor = httpBuilder.getProccessor();
    28 
    29         return proccessor;
    30     }
    31 
    32     public AbstractProccessor getOtherProccessorFirst() {
    33 
    34         this.sequence.clear();
    35         sequence.add("prepare");
    36 
    37         otherBuilder.setSequence(sequence);
    38 
    39         AbstractProccessor proccessor = otherBuilder.getProccessor();
    40 
    41         return proccessor;
    42     }
    43 
    44     public AbstractProccessor getOtherProccessorSecond() {
    45 
    46         this.sequence.clear();
    47         sequence.add("prepare");
    48         sequence.add("after");
    49 
    50         otherBuilder.setSequence(sequence);
    51 
    52         AbstractProccessor proccessor = otherBuilder.getProccessor();
    53 
    54         return proccessor;
    55     }
    56 }

    最后我们在修改一下场景类:

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4 
     5         AbstractProccessor proccessor = null;
     6 
     7         Director director = new Director();
     8         proccessor = director.getHttpProccessorFirst();
     9         proccessor.run(new ExampleContext());
    10 
    11         proccessor = director.getHttpProccessorSecond();
    12         proccessor.run(new ExampleContext());
    13 
    14 
    15         proccessor = director.getOtherProccessorFirst();
    16         proccessor.run(new ExampleContext());
    17 
    18         proccessor = director.getOtherProccessorSecond();
    19         proccessor.run(new ExampleContext());
    20 
    21 
    22 
    23     }
    24 }

    简单而明了,笔者在开发的过程中,遇到很多的开发者不注意代码质量,甚至连资深的技术专家都没有意识到这一点。写下一行代码需要10秒钟,而看懂一行代码确实需要很大的力气。因此设计模式是用简单的方式将复杂的业务需求清晰的表达出来。

    最后总结一下。建造者模式是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

    在建造者模式中有4个角色,分别是产品类,抽象建造者,具体建造者,导演。

    建造者模式的优点

    1.良好的封装:场景类不必知道产品内部的细节。

    2.建造者的独立,良好的扩展:存在不同的具体建造者,每个建造者之间独立。

    3.良好的控制风险:因为具体的建造者是相互独立的,因此建造过程也是独立的,不会某一个建造者的变动对其他造成影响。

  • 相关阅读:
    业余无线电A类考试准备笔记
    关于互联网技术基层绩效管理的一些思考
    适合产品经理的十本书 From 俞军
    从敏捷开发到微服务,maybe再到中台
    Golang内存模型
    CSS中的那点事儿(一)--- CSS中的单位2
    CSS中的那点事儿(一)--- CSS中的单位1
    design.js
    model.js
    云技术相关的概念
  • 原文地址:https://www.cnblogs.com/sunshine798798/p/10032806.html
Copyright © 2020-2023  润新知