由于上一篇里的okhttp使用了builder模式,所以这里分析一下builder模式——建造者模式:
参看:https://www.cnblogs.com/lwbqqyumidi/p/3742562.html
其实建造者模式就是把各种属性都设置好,然后最后再进行类似于build的功能。所以属性特别多的时候建议用这种模式。
那么这些属性的设置有没有次序呢?
所以就分为两种情况:
1、通过Client、Director、Builder和Product形成的有次序的建造者模式
Builder负责Product类对象的具体过程构建
Director负责指导Build,要求Builder按照其指定的顺序去完成Produt的构造。
最后通过Builder返回建造后的结果
(1)建立房子类
package com.zs.zhao.buildertest.unstatic;
/**
* Created by zhao on 2018/11/4.
*/
public class Room {
private Window window;
private Floot floot;
public Window getWindow() {
return window;
}
public void setWindow(Window window) {
this.window = window;
}
public Floot getFloot() {
return floot;
}
public void setFloot(Floot floot) {
this.floot = floot;
}
}
(2)建立build接口,也就是后续build要进行的一系列操作(盖房子啊,铺地砖啊、交房子啊什么的)
package com.zs.zhao.buildertest.unstatic;
/**
* 工人接口,定义了工人所要进行的工作。他们负责进行具体部件如窗户,地板的建造。
* 同时因为房子是民工建的,因此建设完成后由他把房子递交回房主
* Created by zhao on 2018/11/4.
*/
public interface Builder {
public void makeWindow();
public void makeFloor();
public Room getRoom();
}
(3)写出builder接口的实现类:
package com.zs.zhao.buildertest.unstatic;
/**
* 具体的房屋建造工人类
* Created by zhao on 2018/11/4.
*/
public class RoomBuilder implements Builder {
private Room room=new Room();
@Override
public void makeWindow() {
room.setWindow(new Window());
}
@Override
public void makeFloor() {
room.setFloot(new Floot());
}
@Override
public Room getRoom() {
return room;
}
}
这样接下来我们只需要些个设计类来调用这些建造的方法就行了,这样就可以按顺序了。写好我们再调设计类。最后调用getRoom返回room对象就可以了,也就是下面的操作。
(4)
package com.zs.zhao.buildertest.unstatic;
/**
* 定义房子设计师
* Created by zhao on 2018/11/4.
*/
public class Designer {
public void command(Builder builder){
//先建造地板
builder.makeFloor();
//再建造窗户
builder.makeWindow();
}
}
(5)然后再写个调用的客户端:
package com.zs.zhao.buildertest.unstatic;
/**
* Created by zhao on 2018/11/4.
*/
public class Client {
public static void main(String[]args){
//先找个工人来
RoomBuilder roomBuilder = new RoomBuilder();
//再找个设计师来
Designer designer = new Designer();
//工人按照设计师设计建造
designer.command(roomBuilder);
//工人向雇主交房子
Room room = roomBuilder.getRoom();
}
}
看到了吧,所有的操作顺序都被定义在roomBuilder里了。而顺序的保持是通过designer的command传入该builder保证的。那么无序的该怎么写呢?当然就不用设计类啦!直接把builder里方法的返回值还返回为该builder对象,这样就可以一直调下去啦。等全设置好了最后调个.build()。就可以返回我们在builder里设置的这个对象本身啦~(具体看下面,也就是第二种)
2、通过静态内部类等方式实现的无序的构造
package isstatic;
/**
* Created by zhao on 2018/11/4.
*/
public class User {
private String name;
private int age;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public static class Builder{
private User user=new User();
public Builder setName(String name){
user.setName(name);
return this;
}
public Builder setAge(int age) {
user.setAge(age);
return this;
}
public Builder setAddress(String address) {
user.setAddress(address);
return this;
}
public User build(){
return user;
}
}
@Override
public String toString() {
return this.name+"\n"+this.age+"\n"+this.address;
}
}
client:
package isstatic;
/**
* Created by zhao on 2018/11/4.
*/
public class Client {
public static void main(String[] args) {
User user = new User.Builder()
.setName("baobao")
.setAge(1)
.setAddress("dizhi")
.build();
System.out.println(user.toString());
}
}
有没有很像okhttp和alertdialog啊。
那么我去扒一下okhttp的代码,我们来看一下下面这一段:
Request request=new Request.Builder()
.url("http://www.baidu.com")
.header("User-Agent","Okhttp Example")
.build();
那么按刚刚的推理,我们看一下Builder。
确实是个静态内部类。
那么既然是request,这个他的builder最后一定返回了一个通过这些方法传参后的request对象。
我们先看看.url方法
/**
* Sets the URL target of this request.
*
* @throws IllegalArgumentException if {@code url} is not a valid HTTP or HTTPS URL. Avoid this
* exception by calling {@link HttpUrl#parse}; it returns null for invalid URLs.
*/
public Builder url(String url) {
if (url == null) throw new NullPointerException("url == null");
// Silently replace web socket URLs with HTTP URLs.
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
return url(HttpUrl.get(url));
}
最后调用的url(HttpUrl.get(url))
public Builder url(HttpUrl url) {
if (url == null) throw new NullPointerException("url == null");
this.url = url;
return this;
}
最后这一个就相当于个set方法,把url存入了builder的url属性中。(和之前的例子不同,这里没有存入外面的request类的属性中,而是直接设置在了builder里 )
header也是存在了builder里。
设置完进行build()方法:
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
点进去看看new Request(this);
最后通过this对象(builder的)传入new Request(),然后把所有builder的属性传回给Request。但是为什么不是直接使用外面request属性进行存储而是要先用里面的。。这个我暂时也不知道为什么。如果有高手也希望进行下详解。谢谢~~~O(∩_∩)O。