java 19-开发中各类小卡顿

1.jsonObject

JSONObject如何解析json数据

选取这段json数据是因为这段数据还是比较复杂的,能涵盖要说的关键点

{
  "data": {
    "city": "深圳",
    "temphigh": "25",
    "templow": "19",
    "updatetime": "2017-11-04 13:23:00",
    "tempnow": "24",
    "sendibletemp": "27",
    "winddirect": "东北风",
    "windpower": "2级",
    "humidity": "42",
    "sunrise": "06:29",
    "sunset": "17:45",
    "weather": "多云",
    "week": "星期六",
    "nl": null,
    "date": "2017-11-04",
    "index": [
      {
        "name": "化妆指数",
        "level": "控油",
        "msg": "建议用露质面霜打底,水质无油粉底霜,透明粉饼,粉质胭脂。"
      },
      {
        "name": "感冒指数",
        "level": "易发",
        "msg": "感冒容易发生,少去人群密集的场所有利于降低感冒的几率。"
      },
      {
        "name": "洗车指数",
        "level": "不宜",
        "msg": "雨(雪)水和泥水会弄脏您的爱车,不适宜清洗车辆。"
      },
      {
        "name": "穿衣指数",
        "level": "舒适",
        "msg": "白天温度适中,但早晚凉,易穿脱的便携外套很实用。"
      },
      {
        "name": "紫外线强度指数",
        "level": "",
        "msg": "辐射较弱,涂擦SPF12-15、PA+护肤品。"
      },
      {
        "name": "运动指数",
        "level": "不适宜",
        "msg": "受到阵雨天气的影响,不宜在户外运动。"
      }
    ],
    "pm25": {
      "aqi": 0,
      "co": 8,
      "o3": 42,
      "pm10": 63,
      "pm2_5": 64,
      "quality": "",
      "so2": 4,
      "no2": 11,
      "updatetime": "2017-11-04 13:00:00"
    },
    "daily": [
      {
        "date": "2017-11-04",
        "week": "星期六",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "25",
        "templow": "19",
        "weather": "多云"
      },
      {
        "date": "2017-11-05",
        "week": "星期日",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "26",
        "templow": "19",
        "weather": "多云"
      },
      {
        "date": "2017-11-06",
        "week": "星期一",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "27",
        "templow": "20",
        "weather": "多云"
      },
      {
        "date": "2017-11-07",
        "week": "星期二",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "28",
        "templow": "21",
        "weather": "多云"
      },
      {
        "date": "2017-11-08",
        "week": "星期三",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "29",
        "templow": "22",
        "weather": "多云"
      },
      {
        "date": "2017-11-09",
        "week": "星期四",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "28",
        "templow": "22",
        "weather": "多云"
      },
      {
        "date": "2017-11-03",
        "week": "星期五",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "28",
        "templow": "18",
        "weather": ""
      }
    ]
  },
  "status": 0,
  "msg": "ok"
}

解析JSON

利用JSONString进行简单解析

我利用了RxVolley进行数据通信,t为API返回的数据

RxVolley.get("https://chkj02.market.alicloudapi.com/qgtq?city="+city, params, new HttpCallback() {
    @Override
    public void onSuccess(String t) {
        Loger.debug("请求到的数据:" + t);
    }
});

我们现在要获取这部分数据,该如何进行解析呢?

首先,将t中的数据传到JSONObject类型的jsonObject中,再通过getJSONObject获取到data下的数据。

//解析数据
JSONObject jsonObject = new JSONObject(t);
JSONObject jsonData = jsonObject.getJSONObject("data");

此时,jsonData中数据为

{
    "city": "深圳",
    "temphigh": "25",
    "templow": "19",
    "updatetime": "2017-11-04 13:23:00",
    "tempnow": "24",
    "sendibletemp": "27",
    "winddirect": "东北风",
    "windpower": "2级",
    "humidity": "42",
    "sunrise": "06:29",
    "sunset": "17:45",
    "weather": "多云",
    "week": "星期六",
    "nl": null,
    "date": "2017-11-04"
}

然后通过getString进行读值即可

//解析天气
String jsonTemplow = jsonData.getString("templow");
String jsonTempHigh = jsonData.getString("temphigh");
String jsonWeather = jsonData.getString("weather");
String jsonTempnow = jsonData.getString("tempnow");
String jsonWinddirect = jsonData.getString("winddirect");
String jsonWindpower = jsonData.getString("windpower");
String jsonHumidity = jsonData.getString("humidity");
利用JSONArray进行复杂解析

这次,我们要获取这部分数据

首先,将t中的数据传到JSONObject类型的jsonObject中,再通过getJSONObject获取到data下的数据。然后jsonArray通过getJSONArray获得index下的数据

//解析数据
JSONObject jsonObject = new JSONObject(t);
JSONObject jsonData = jsonObject.getJSONObject("data");
JSONArray jsonIndex =jsonData.getJSONArray("index");
JSONArray jsonDaily =jsonData.getJSONArray("daily");

方法一

此时,jsonDaily中数据为

[
      {
        "date": "2017-11-04",
        "week": "星期六",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "25",
        "templow": "19",
        "weather": "多云"
      },
      {
        "date": "2017-11-05",
        "week": "星期日",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "26",
        "templow": "19",
        "weather": "多云"
      },
      {
        "date": "2017-11-06",
        "week": "星期一",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "27",
        "templow": "20",
        "weather": "多云"
      },
      {
        "date": "2017-11-07",
        "week": "星期二",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "28",
        "templow": "21",
        "weather": "多云"
      },
      {
        "date": "2017-11-08",
        "week": "星期三",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "29",
        "templow": "22",
        "weather": "多云"
      },
      {
        "date": "2017-11-09",
        "week": "星期四",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "28",
        "templow": "22",
        "weather": "多云"
      },
      {
        "date": "2017-11-03",
        "week": "星期五",
        "sunrise": "06:29",
        "sunset": "17:45",
        "temphigh": "28",
        "templow": "18",
        "weather": ""
      }
]

把jsonDaily中按分类进行解析,分为几个ArrayList<>,datesweeksweathers等,然后进行for循环。

List<String> dates = new ArrayList<>();
List<String> weeks = new ArrayList<>();
List<String> weathers = new ArrayList<>();

int j=1;
for (int i=0;i<jsonDaily.length();i++){
    JSONObject partDaily = jsonDaily.getJSONObject(i);
    JSONString date = partDaily.getString("date");
    dates.add(date);
    JSONString week = partDaily.getString("week");
    weeks.add(week);
    JSONString weather = partDaily.getString("weather");
    weathers.add(weather);
}

方法二

此时,jsonIndex中数据为

 [
      {
        "name": "化妆指数",
        "level": "控油",
        "msg": "建议用露质面霜打底,水质无油粉底霜,透明粉饼,粉质胭脂。"
      },
      {
        "name": "感冒指数",
        "level": "易发",
        "msg": "感冒容易发生,少去人群密集的场所有利于降低感冒的几率。"
      },
      {
        "name": "洗车指数",
        "level": "不宜",
        "msg": "雨(雪)水和泥水会弄脏您的爱车,不适宜清洗车辆。"
      },
      {
        "name": "穿衣指数",
        "level": "舒适",
        "msg": "白天温度适中,但早晚凉,易穿脱的便携外套很实用。"
      },
      {
        "name": "紫外线强度指数",
        "level": "",
        "msg": "辐射较弱,涂擦SPF12-15、PA+护肤品。"
      },
      {
        "name": "运动指数",
        "level": "不适宜",
        "msg": "受到阵雨天气的影响,不宜在户外运动。"
      }
]

jsonIndex为二维数组,我们通过两个嵌套循环进行遍历。首先,外层根据数组长度进行for循环遍历;然后内层使用迭代器进行遍历。

String[] jsonIndex = new String[20];//数组长度声明为20确保够用
int j=1;
for (int i=0;i<jsonArray.length();i++){
    JSONObject partIndex =jsonIndex.getJSONObject(i);
    Iterator iterator = partIndex.keys();
    String key;
    while(iterator.hasNext()){
        //hasNext方法,只是判断下一个元素的有无,并不移动指针
        key = (String) iterator.next();//next方法,向下移动指针,并且返回指针指向的元素,如果指针指向的内存中没有元素,会报异常
        jsonIndex[j] = partIndex.getString(key);
        j++;
    }
}

这样此指数数据就被我们成功解析,然后存入jsonIndex数组中。



2.Map

Map<String, String> 遍历的四种方法

  Map<String, String> map = new HashMap<String, String>();
  map.put("key1", "value1");
  map.put("key2", "value2");
  map.put("key3", "value3");

  //第一种:普遍使用,二次取值
  System.out.println("通过Map.keySet遍历key和value:");
  for (String key : map.keySet()) {
   System.out.println("key= "+ key + " and value= " + map.get(key));
  }

  //第二种
  System.out.println("通过Map.entrySet使用iterator遍历key和value:");
  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
  while (it.hasNext()) {
   Map.Entry<String, String> entry = it.next();
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }

  //第三种:推荐,尤其是容量大时
  System.out.println("通过Map.entrySet遍历key和value");
  for (Map.Entry<String, String> entry : map.entrySet()) {
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }

  //第四种
  System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
  for (String v : map.values()) {
   System.out.println("value= " + v);
  }

JSONObject和String相互转换

JSONObject jsonObject = new JSONObject();
       JSONArray jsonArray = new JSONArray();
       try {
           jsonObject.put("a","1");
           jsonObject.put("b","2");
           jsonObject.put("c","3");
           jsonObject.put("d","4");
           for(int i=0;i<10;i++){
               JSONObject object = new JSONObject();
               object.put("name",i+"");
               jsonArray.put(object);
           }
           jsonObject.put("abcd",jsonArray);
       } catch (JSONException e) {
           e.printStackTrace();
       }

       Log.e("MainActivity",jsonObject.toString());

       try {
           JSONObject object = new JSONObject(jsonObject.toString());
           Log.e("MainActivity",object.toString());

       } catch (JSONException e) {
           e.printStackTrace();
       }

输出结果

11-13 14:14:13.846 15433-15433/com.example.apple.demo E/MainActivity:<br> {"a":"1","b":"2","c":"3","d":"4","abcd":[{"name":"0"},{"name":"1"},{"name":"2"},{"name":"3"},{"name":"4"},{"name":"5"},{"name":"6"},{"name":"7"},{"name":"8"},{"name":"9"}]}
11-13 14:14:13.846 15433-15433/com.example.apple.demo E/MainActivity: <br>{"a":"1","b":"2","c":"3","d":"4","abcd":[{"name":"0"},{"name":"1"},{"name":"2"},{"name":"3"},{"name":"4"},{"name":"5"},{"name":"6"},{"name":"7"},{"name":"8"},{"name":"9"}]}

JSONObject和Map相互转换,这个转换需要一个第三方的库文件,我比较喜欢用FastJson,具体使用请看我的另外一篇博客

HashMap<String,String>map = new HashMap<>();
map.put("a","1");
map.put("b","2");
map.put("c","3");

String json = JSON.toJSONString(map);//map转String
JSONObject jsonObject = JSON.parseObject(json);//String转json

//json转map
 Map<String, String> jsonMap = JSONObject.toJavaObject(jsonObject, Map.class);
 //String转map
 Map<String, String> jsonMap1 = JSONObject.parseObject(json, Map.class);




3.通用Response类

BaseResponse.class

package com.chenglulu.controller.users.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.omg.CORBA.Any;

@Data
public class BaseResponse<T> {
    public BaseResponse() {
        super();
    }

    private String requestId;

    private String message;

    private Integer code;

    private T data;

    public BaseResponse(String requestId, Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
        this.requestId = requestId;
    }

}

ResponseUtil.class

package com.chenglulu.utils;

import com.chenglulu.enums.ResponseEnum;
import com.chenglulu.controller.users.domain.BaseResponse;

public class ResponseUtil {
    /**成功且带数据**/
    public static BaseResponse success(String requestId, Object object){
        BaseResponse res = new BaseResponse();
        res.setRequestId(requestId);
        res.setCode(ResponseEnum.SUCCESS.getCode());
        res.setMessage(ResponseEnum.SUCCESS.getMessage());
        res.setData(object);
        return res;
    }
    /**成功但不带数据**/
    public static BaseResponse success(String requestId){
        BaseResponse result = new BaseResponse();
        res.setRequestId(requestId);
        return success(null);
    }
    /**失败**/
    public static BaseResponse error(String requestId, Integer code,String msg){
        BaseResponse result = new BaseResponse();
        res.setRequestId(requestId);
        result.setCode(code);
        result.setMessage(msg);
        return result;
    }
}

ResponseCodeEnum枚举类

package com.chenglulu.enums;

public enum ResponseCodeEnum {
    //这里是可以自己定义的,方便与前端交互即可
    UNKNOWN_ERROR(-1,"未知错误"),
    SUCCESS(10000,"成功"),
    USER_NOT_EXIST(1,"用户不存在"),
    USER_IS_EXISTS(2,"用户已存在"),
    DATA_IS_NULL(3,"数据为空"),
    ;

    private Integer code;
    private String message;

    ResponseCodeEnum(Integer code, String message){
        this.code = code;
        this.message = message;
    }

    public Integer getCode(){
        return code;
    }

    public String getMessage(){
        return message;
    }
}

使用示例

import com.chenglulu.utils.ResponseUtil;

@RestController
@RequestMapping( value = "/users")
public class UsersController {

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public BaseResponse queryUsers(HttpServletRequest request){
        String requestId = request.getHeader("X-REQUEST-ID");
        List<Users> usersList = [];
        return ResponseUtil.success(requestId, usersList);
    }
}


4.TODO

刚好看到阿里巴巴开发规范的对于TODO的说明,粘贴出来有需要的可以参考

【参考】特殊注释标记,请注明标记人与标记时间。注意及时处理这些标记,通过标记扫描, 经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。 

1) 待办事宜(TODO):( 标记人,标记时间,[预计处理时间])    表示需要实现,但目前还未实现的功能。  这实际上是一个 Javadoc 的标签,目前的 Javadoc 还没有实现,但已经被广泛使用。只能应用于类,接口和方法(因为它是一个 Javadoc 标签)。 

2) 错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间])    在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况

需要阿里巴巴Java开发手册(1.4.0版本)以及插件 可以去官方的GitHub上下载:https://github.com/alibaba/p3c

其实就是类似于标记的作用,可以很快的定位到这个位置,方便查找,如图:

在这里插入图片描述


5.lambada表达式

          Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。

(parameters) -> expression
或
(parameters) ->{ statements; }

以下是lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

Lambda 表达式实例

// 1. 不需要参数,返回值为 5  
() -> 5

// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x

// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y

// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y

// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

在 Java8Tester.java 文件输入以下代码:

public class Java8Tester {
   public static void main(String args[]){
      Java8Tester tester = new Java8Tester();

      // 类型声明
      MathOperation addition = (int a, int b) -> a + b;

      // 不用类型声明
      MathOperation subtraction = (a, b) -> a - b;

      // 大括号中的返回语句
      MathOperation multiplication = (int a, int b) -> { return a * b; };

      // 没有大括号及返回语句
      MathOperation division = (int a, int b) -> a / b;

      System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
      System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
      System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));

      // 不用括号
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);

      // 用括号
      GreetingService greetService2 = (message) ->
      System.out.println("Hello " + message);

      greetService1.sayMessage("Runoob");
      greetService2.sayMessage("Google");
   }

   interface MathOperation {
      int operation(int a, int b);
   }

   interface GreetingService {
      void sayMessage(String message);
   }

   private int operate(int a, int b, MathOperation mathOperation){
      return mathOperation.operation(a, b);
   }
}


6.设计模式之 建造者模式 Builder pattern

在软件工程领域,设计模式是一套通用的可复用的解决方案,用来解决在软件设计过程中产生的通用问题。它不是一个可以直接转换成源代码的设计,只是一套在软件系统设计过程中程序员应该遵循的最佳实践准则。工作中常常出现建造者模式的身影,所以整理记录一下,希望对自己和其他人都有一个帮助。希望你读完本文后可以在实际开发过程中用上Builder 模式,成功装一把逼,书生我就甚是欣慰了。Builder pattern将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示

当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

解决的问题

当一个类的构造函数参数超过4个,而且这些参数有些是可选的时,我们通常有两种办法来构建它的对象。 例如我们现在有如下一个类计算机类Computer,其中cpu与ram是必填参数,而其他3个是可选参数,那么我们如何构造这个类的实例呢,通常有两种常用的方式:

public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选
}
第一:折叠构造函数模式(telescoping constructor pattern ),这个我们经常用,如下代码所示
public class Computer {
     ...
    public Computer(String cpu, String ram) {
        this(cpu, ram, 0);
    }
    public Computer(String cpu, String ram, int usbCount) {
        this(cpu, ram, usbCount, "罗技键盘");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard) {
        this(cpu, ram, usbCount, keyboard, "三星显示器");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard, String display) {
        this.cpu = cpu;
        this.ram = ram;
        this.usbCount = usbCount;
        this.keyboard = keyboard;
        this.display = display;
    }
}
第二种:Javabean 模式,如下所示
public class Computer {
        ...

    public String getCpu() {
        return cpu;
    }
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }
    public String getRam() {
        return ram;
    }
    public void setRam(String ram) {
        this.ram = ram;
    }
    public int getUsbCount() {
        return usbCount;
    }
...
}

那么这两种方式有什么弊端呢?

第一种主要是使用及阅读不方便。你可以想象一下,当你要调用一个类的构造函数时,你首先要决定使用哪一个,然后里面又是一堆参数,如果这些参数的类型很多又都一样,你还要搞清楚这些参数的含义,很容易就传混了。。。那酸爽谁用谁知道。

第二种方式在构建过程中对象的状态容易发生变化,造成错误。因为那个类中的属性是分步设置的,所以就容易出错。

为了解决这两个痛点,builder模式就横空出世了。

如何实现

  1. 在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。
  2. 在Computer中创建一个private的构造函数,参数为Builder类型
  3. 在Builder中创建一个public的构造函数,参数为Computer中必填的那些参数,cpu 和ram。
  4. 在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例
  5. 在Builder中创建一个build()方法,在其中构建Computer的实例并返回

下面代码就是最终的样子

public class Computer {
    private final String cpu;//必须
    private final String ram;//必须
    private final int usbCount;//可选
    private final String keyboard;//可选
    private final String display;//可选

    private Computer(Builder builder){
        this.cpu=builder.cpu;
        this.ram=builder.ram;
        this.usbCount=builder.usbCount;
        this.keyboard=builder.keyboard;
        this.display=builder.display;
    }
    public static class Builder{
        private String cpu;//必须
        private String ram;//必须
        private int usbCount;//可选
        private String keyboard;//可选
        private String display;//可选

        public Builder(String cup,String ram){
            this.cpu=cup;
            this.ram=ram;
        }

        public Builder setUsbCount(int usbCount) {
            this.usbCount = usbCount;
            return this;
        }
        public Builder setKeyboard(String keyboard) {
            this.keyboard = keyboard;
            return this;
        }
        public Builder setDisplay(String display) {
            this.display = display;
            return this;
        }
        public Computer build(){
            return new Computer(this);
        }
    }
  //省略getter方法
}

如何使用

在客户端使用链式调用,一步一步的把对象构建出来。

Computer computer=new Computer.Builder("因特尔","三星")
                .setDisplay("三星24寸")
                .setKeyboard("罗技")
                .setUsbCount(2)
                .build();

案例

构建者模式是一个非常实用而常见的创建类型的模式(creational design pattern),例如图片处理框架Glide,网络请求框架Retrofit等都使用了此模式。

扩展

其实上面的内容是Builder在Java中一种简化的使用方式,经典的Builder 模式与其有一定的不同,如果没有兴趣的同学就可以不用往下读了。

传统Builder 模式

构建者模式UML图如下所示


如上图所示,builder模式有4个角色。

  • Product: 最终要生成的对象,例如 Computer实例。
  • Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()
  • ConcreteBuilder: Builder的实现类。
  • Director: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct() 方法获得最终的产品。

我们接下来将最开始的例子使用传统方式来实现一遍。

第一步:我们的目标Computer类:

public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选

    public Computer(String cpu, String ram) {
        this.cpu = cpu;
        this.ram = ram;
    }
    public void setUsbCount(int usbCount) {
        this.usbCount = usbCount;
    }
    public void setKeyboard(String keyboard) {
        this.keyboard = keyboard;
    }
    public void setDisplay(String display) {
        this.display = display;
    }
    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram='" + ram + '\'' +
                ", usbCount=" + usbCount +
                ", keyboard='" + keyboard + '\'' +
                ", display='" + display + '\'' +
                '}';
    }
}

第二步:抽象构建者类

public abstract class ComputerBuilder {
    public abstract void setUsbCount();
    public abstract void setKeyboard();
    public abstract void setDisplay();

    public abstract Computer getComputer();
}

第三步:实体构建者类,我们可以根据要构建的产品种类产生多了实体构建者类,这里我们需要构建两种品牌的电脑,苹果电脑和联想电脑,所以我们生成了两个实体构建者类。

苹果电脑构建者类

public class MacComputerBuilder extends ComputerBuilder {
    private Computer computer;
    public MacComputerBuilder(String cpu, String ram) {
        computer = new Computer(cpu, ram);
    }
    @Override
    public void setUsbCount() {
        computer.setUsbCount(2);
    }
    @Override
    public void setKeyboard() {
        computer.setKeyboard("苹果键盘");
    }
    @Override
    public void setDisplay() {
        computer.setDisplay("苹果显示器");
    }
    @Override
    public Computer getComputer() {
        return computer;
    }
}

联想电脑构建者类

public class LenovoComputerBuilder extends ComputerBuilder {
    private Computer computer;
    public LenovoComputerBuilder(String cpu, String ram) {
        computer=new Computer(cpu,ram);
    }
    @Override
    public void setUsbCount() {
        computer.setUsbCount(4);
    }
    @Override
    public void setKeyboard() {
        computer.setKeyboard("联想键盘");
    }
    @Override
    public void setDisplay() {
        computer.setDisplay("联想显示器");
    }
    @Override
    public Computer getComputer() {
        return computer;
    }
}

第四步:指导者类(Director)

public class ComputerDirector {
    public void makeComputer(ComputerBuilder builder){
        builder.setUsbCount();
        builder.setDisplay();
        builder.setKeyboard();
    }
}

使用

首先生成一个director (1),然后生成一个目标builder (2),接着使用director组装builder (3),组装完毕后使用builder创建产品实例 (4)。

public static void main(String[] args) {
        ComputerDirector director=new ComputerDirector();//1
        ComputerBuilder builder=new MacComputerBuilder("I5处理器","三星125");//2
        director.makeComputer(builder);//3
        Computer macComputer=builder.getComputer();//4
        System.out.println("mac computer:"+macComputer.toString());

        ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7处理器","海力士222");
        director.makeComputer(lenovoBuilder);
        Computer lenovoComputer=lenovoBuilder.getComputer();
        System.out.println("lenovo computer:"+lenovoComputer.toString());
}

输出结果如下:

mac computer:Computer{cpu='I5处理器', ram='三星125', usbCount=2, keyboard='苹果键盘', display='苹果显示器'}
lenovo computer:Computer{cpu='I7处理器', ram='海力士222', usbCount=4, keyboard='联想键盘', display='联想显示器'}
可以看到,文章最开始的使用方式是传统builder模式的变种, 首先其省略了director 这个角色,将构建算法交给了client端,其次将builder 写到了要构建的产品类里面,最后采用了链式调用。
posted @ 2021-02-25 10:11  芒果侠  阅读(102)  评论(0编辑  收藏  举报