三颗纽扣

世界上最宽广的是海洋,比海洋更宽广的是天空,比天空更宽广的是人的胸怀

导航

Builder 链——另类一点的Builder模式

对象创建的Builder模式中 一文中的 Builder 模式应该说还是蛮有用的,然而很多时候它还是有一点点不方便,例如 对象的属性比较多的时候,常常会比较担心 “有没有漏掉那个属性没有初始化呢?”,今天灵感突现,给这个问题找到了一个还算是不错的解决方案,我称之为 Builder 链,虽然代码稍微有点复杂,不过如果结合一个 “生成 Builder ”的代码生成工具的话,应该就可以圆满了。

 

场景:需要构造一些这样的 URL  [cc:][//server[:port]]/[volume]/partition[:version][//filename] , 这里很多 [] 中的那些部分表示是可以省略的,因此使用了这样一个 Builder

    private static class CCUrlBuilder {
        
private String cc;
        
private String server;
        
private String port;
        
private String volume;
        
private String partition;
        
private String version;
        
private String filename;

    ... ...

采用通常的 Builder 模式写法,那么每次在 urlBuilder 后面按下句点时,IDE 将弹出相应的一系列 setXXXX 方法,问题就在于我们需要从这一系列方法中挑出一个,并且要保证最后所有的 setXXXX 方法都被调用过了一次,属性太多的时候,这就成了一个大问题。

因此,现在我们这样来写这个 Builder

private static class CCUrlBuilder {
    
private String cc;
    
private String server;
    
private String port;
    
private String volume;
    
private String partition;
    
private String version;
    
private String filename;
    
    
private ServerSetter serverSetter = new ServerSetter();
    
private PortSetter portSetter = new PortSetter();
    
private VolumeSetter volumeSetter = new VolumeSetter();
    
private PartitionSetter partitionSetter = new PartitionSetter();
    
private VersionSetter versionSetter = new VersionSetter();
    
private FilenameSetter filenameSetter = new FilenameSetter();
    
    
public static CCUrlBuilder start() {
        
return new CCUrlBuilder();
    }
    
    
public String get() {
        
//      [cc:][//server[:port]]/[volume]/partition[:version][//filename]
        StringBuilder sb = new StringBuilder();
        
if (cc!=null) sb.append(cc);
        
if (server!=null) sb.append("//").append(server);
        
if (port!=null) sb.append(":").append(port);
        sb.append(
"/").append(volume == null? "" : volume);
        sb.append(
"/").append(partition);
        
if (version!=null) sb.append(":").append(version);
        
if (filename!=null) sb.append("//").append(filename);
        
return sb.toString();
    }
    
    
public ServerSetter setCc(String cc) {
        
this.cc = cc;
        
return serverSetter;
    }
    
public ServerSetter setCc() {
        
return serverSetter;
    }
    
private class ServerSetter {
        
public PortSetter setServer(String value) {
            server 
= value;
            
return portSetter;
        }
        
public PortSetter setServer() {
            
return portSetter;
        }
    }
    
private class PortSetter {
        
public VolumeSetter setPort(int value) {
            port 
= Integer.toString(value);
            
return volumeSetter;
        }
        
public VolumeSetter setPort() {
            
return volumeSetter;
        }
    }
    
private class VolumeSetter {
        
public PartitionSetter setVolume (String value) {
            volume 
= value;
            
return partitionSetter;
        }
        
public PartitionSetter setVolume () {
            
return partitionSetter;
        }
    }
    
public class PartitionSetter {
        
public VersionSetter setPartition (String value) {
            partition 
= value;
            
return versionSetter;
        }
        
public VersionSetter setPartition () {
            
return versionSetter;
        }
    }
    
public class VersionSetter {
        
public FilenameSetter setVersion(int value) {
            version 
= Integer.toString(value);
            
return filenameSetter;
        }
        
public FilenameSetter setVersion() {
            
return filenameSetter;
        }
    }
    
public class FilenameSetter {
        
public CCUrlBuilder setFilename(String value) {
            filename 
= value;
            
return CCUrlBuilder.this;
        }
        
public CCUrlBuilder setFilename() {
            
return CCUrlBuilder.this;
        }
    }
}


贴这么大一段代码实在是情非所愿,不过这段代码本身应该已经说明了这种模式所采用的方法,简单的说,就是用很多的内部类来代替原来 Builder 中的 setXXXX 方法,每个类只提供一个 setXXXX 方法,并返回下一个类,最后再回到 Builder 本身,通过 get() 方法返回构造好的对象。

这样做最大的好处就是由于所有的 XXXXSetter 类,构成了一个链,所以在使用 Builder 的时候,将迫使我们必须将所有的属性都过一篇才能最后回到 Builder 本身,自然就不会遗漏任何一个属性了,其次,每次按下 句点 符号时,IDE 只会弹出唯一的一个 setXXXX 方法,不需要费心 去挑选了,最后,这些 Setter 类还提供了无参的方法,可以方便我们快速的跳过一个属性的设置,但又不会再代码上留下空白,一眼看过,就知道跳过了那些属性,以后要补上这些跳过的属性也非常的方便。

 

 

posted on 2010-04-01 20:49  三颗纽扣  阅读(314)  评论(0编辑  收藏  举报