|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
讲设计模式的大多都很枯燥,而且都用一些比较专业的术语去描述设计模式的角色。GOF的《设计模式》更吓人,推荐一本叫做《大话设计模式》的书籍,把设计模式讲的很有趣,配图和故事都很萌。前两天重构公司代码的一个http client的二次封装类,众所周知的是http请求参数很多,除了正常的请求url、参数之外还有http头部信息,这些东西放请求方法的参数里简直没法看:
- public static String httpPost(String url,String json,String charset,int socketTimeout,int connectTimeOut,Map<String,String> headers){
- //...此处省略一万个字
- }
复制代码
在《代码整洁之道》中,方法参数是禁止超过3个的,超过3个人阅读起来非常不舒服,这里已经6个了。《代码整洁之道》提倡把超过3个参数的封装到类中。也就是说我们可以把httpPost方法中的6个参数抽成这样:
- public static String httpPost(HttpPostParam param){
- //...此处继续省略一万个字
- }
复制代码
那HttpPostParam自然就是对6个参数的setget了:
- public class HttpPostParam{
- private String url;
- private String json;
- private String charset;
- private Integer socketTimeout;
- private Integer connectTimeOut;
- private Map<String,String> headers;
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- public String getJson() {
- return json;
- }
- public void setJson(String json) {
- this.json = json;
- }
- public String getCharset() {
- return charset;
- }
- public void setCharset(String charset) {
- this.charset = charset;
- }
- public Integer getSocketTimeout() {
- return socketTimeout;
- }
- public void setSocketTimeout(Integer socketTimeout) {
- this.socketTimeout = socketTimeout;
- }
- public Integer getConnectTimeOut() {
- return connectTimeOut;
- }
- public void setConnectTimeOut(Integer connectTimeOut) {
- this.connectTimeOut = connectTimeOut;
- }
- public Map<String, String> getHeaders() {
- return headers;
- }
- public void setHeaders(Map<String, String> headers) {
- this.headers = headers;
- }
- }
复制代码
可以说这是我们最常用的方法了,用setget为属性进行赋值。但是在使用该类的时候,我们需要new一个对象然后挨个set方法调用,如果我们的参数更多,那书写起来更不方便,看着也不舒服,我们的代码将会被大量的set方法调用所污染:
- @Test
- public void testHttpPost(){
- HttpPostParam param=new HttpPostParm();
- param.setUrl("http://www.baidu.com");
- param.setJson("{'test':'test'}");
- param.setCharset("UTF-8");
- param.setSocketTimeout(1000);
- param.setConnectTimeOut(1000);
- Map<String,String> headers=new HashMap<>();
- headers.put("Connection","Keep-Alive");
- param.setHeaders(headers);
- HttpClientUtil.httpPost(param);//实际调用方法就一行
- }
复制代码
有人可能会说给HttpPostParam加入构造函数把参数传进去,尤其是可以使用编译器的快捷键自动生成带参数的构造函数:
- public HttpPostParam(String url, String json, String charset, Integer socketTimeout, Integer connectTimeOut, Map<String, String> headers) {//构造函数参数依然看着这么累
- this.url = url;
- this.json = json;
- this.charset = charset;
- this.socketTimeout = socketTimeout;
- this.connectTimeOut = connectTimeOut;
- this.headers = headers;
- }
- public HttpPostParam(String url, String json, String charset, Integer socketTimeout, Integer connectTimeOut) {//如果有的参数不用还得写重载
- this.url = url;
- this.json = json;
- this.charset = charset;
- this.socketTimeout = socketTimeout;
- this.connectTimeOut = connectTimeOut;
- }
复制代码
这样调用起来自然很方便:
- @Test
- public void testHttpPost(){
- Map<String,String> headers=new HashMap<>();
- headers.put("Connection","Keep-Alive");
- param.setHeaders(headers);
- HttpClientUtil.httpPost(new HttpPostParm(
- "http://www.baidu.com",
- "{'test':'test'}",
- "UTF-8",
- 1000,
- 1000,
- headers
- ));//实际调用方法就一行
- }
复制代码
但是,当这样参数加减可就要重新生成构造函数了。
于是想想之前用的google公司开源的protobuf用到的builder,那也来试试吧!
首先模仿下protobuf的Builder使用方法:
- @Test
- public void testHttpPost(){
- Map<String,String> headers=new HashMap<>();
- headers.put("Connection","Keep-Alive");
- param.setHeaders(headers);
- HttpClientUtil.httpPost(
- HttpPostParam.Builder.newBuilder().
- .setUrl("http://www.baidu.com")
- .setJson("{'test':'test'}")
- .setCharset("UTF-8")
- .setSocketTimeout(1000)
- .setConnectTimeOut(1000)
- .setHeaders(headers)
- .build()
- )); //这似乎好读了一些,直接build构建对象,同时不要的属性可以不用set,不会像构造函数那样需要重载好几个版本
- }
复制代码
整体来说都很和谐,接下来看看实现:
- pulic class HttpPostParam{
- private String url;
- private String json;
- private String charset;
- private Integer socketTimeout;
- private Integer connectTimeOut;
- private Map<String,String> headers;
- //④构造函数中把builder传进来,把builder中赋过值的属性逐一赋值给成员变量,这样对于外部调用者直接get就拿到值了
- private HttpPostParam(Builder builder) {
- this.url = builder.url;
- this.json = builder.json;
- this.charset = builder.charset;
- this.socketTimeout = builder.socketTimeout;
- this.connectTimeOut = builder.connectTimeOut;
- this.headers = builder.headers;
- }
- static class Builder {
- private String url;
- private String json;
- private String charset;
- private Integer socketTimeout;
- private Integer connectTimeOut;
- private Map<String, String> headers;
- //①创建个builder对象
- public static Builder newBuilder() {
- return new Builder();
- }
- //③最后创建HttpPostParam对象并且把builder自己传给HttpPostParam的构造函数
- public HttpPostParam build() {
- return new HttpPostParam(this);
- }
- //②对builder中的成员进行赋值。同时返回this,这样做到链式编程。其他的成员属性相同,略。
- public Builder setUrl(String url) {
- this.url = url;
- return this;
- }
- public Builder setJson(String json) {
- this.json = json;
- return this;
- }
- public Builder setCharset(String charset) {
- this.charset = charset;
- return this;
- }
- public Builder setSocketTimeout(Integer socketTimeout) {
- this.socketTimeout = socketTimeout;
- return this;
- }
- public Builder setConnectTimeOut(Integer connectTimeOut) {
- this.connectTimeOut = connectTimeOut;
- return this;
- }
- public Builder setHeaders(Map<String, String> headers) {
- this.headers = headers;
- return this;
- }
- }
- public String getUrl() {
- return url;
- }
- public String getJson() {
- return json;
- }
- public String getCharset() {
- return charset;
- }
- public Integer getSocketTimeout() {
- return socketTimeout;
- }
- public Integer getConnectTimeOut() {
- return connectTimeOut;
- }
- public Map<String, String> getHeaders() {
- return headers;
- }
- }
复制代码
可以看到HttpPostParam被分成两层,外层只有get方法用来获取属性,而内层构造了个静态内部类叫Builder。通过Builder的newBuilder来创建Builder对象,然后调用Builder中的set方法对属性进行赋值,需要注意的是set方法返回了builder本身,这样在外部调用的时候就可以做到链式编程,即:setUrl().setHeaders()...,在赋值之后使用对外提供的build方法把当前对象直接通过构造参数传给HttpPostParam的实例,HttpPostParam的构造函数中对外层的HttpPostParam成员变量进行了赋值。
整体流程其实不复杂,总体来说Builder模式会比单纯的setget方法构造出的类要复杂一些而且代码量多,但是要比单纯的setget和构造函数传参要灵活可变,把可变性进行了封装,api可读性强,操作也简单了一些。
另外,如果需要一些必要的参数,可以直接在Builder的newBuilder中指出:
- //其他的代码略,这里只给出newBuilder的写法
- public static Builder newBuilder(String url) {
- this.url=url;
- return new Builder();
- }
复制代码
builder模式在设计模式中属于建造类型的模式,相对来说比较简单。推荐使用builder模式代替通常的bean或entity的setget方法。
|
评分
-
查看全部评分
|