惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
爱范儿
爱范儿
T
The Exploit Database - CXSecurity.com
量子位
T
Tailwind CSS Blog
T
Threatpost
The GitHub Blog
The GitHub Blog
AWS News Blog
AWS News Blog
云风的 BLOG
云风的 BLOG
K
Kaspersky official blog
P
Proofpoint News Feed
博客园 - 司徒正美
L
LangChain Blog
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 叶小钗
S
Secure Thoughts
The Last Watchdog
The Last Watchdog
Spread Privacy
Spread Privacy
H
Hacker News: Front Page
T
Troy Hunt's Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Google DeepMind News
Google DeepMind News
W
WeLiveSecurity
A
Arctic Wolf
Apple Machine Learning Research
Apple Machine Learning Research
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Proofpoint News Feed
T
Tor Project blog
T
The Blog of Author Tim Ferriss
I
Intezer
P
Privacy & Cybersecurity Law Blog
美团技术团队
N
Netflix TechBlog - Medium
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost
Application and Cybersecurity Blog
Application and Cybersecurity Blog
G
Google Developers Blog
Attack and Defense Labs
Attack and Defense Labs
T
Tenable Blog
月光博客
月光博客
Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
腾讯CDC
Microsoft Security Blog
Microsoft Security Blog
A
About on SuperTechFans
Last Week in AI
Last Week in AI

博客园 - 三颗纽扣

windows下安装redmine-2.1 try-cache-finally 在线程被杀掉时还有作用吗? 使用InfoBright实现20-100亿条原始话单记录的检索 Hibernate乐观锁真的会抛出异常吗? 并非文学化编程,在VS环境下的折中方案 快速复制NuGet引用 语义版本规范 基础框架的基础组件 在 IIS 6 上架设 NuGet Server DotNet开发利器之MyEclipseShortcuts 通过 POI 获取图片在 Excel 表格中的位置 我们是原始生物 没有别的,只有天使 灯是用来照亮的,而不是引路的 戒了,过去完成时 我送给你们的,没有别的——只有天使。 多线程JUnit单元测试:GroboUtils and ConTest 控制内存的使用之二:对象缓存 pool and cache 控制内存的使用
Builder 链——另类一点的Builder模式
三颗纽扣 · 2010-04-01 · via 博客园 - 三颗纽扣

对象创建的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 类还提供了无参的方法,可以方便我们快速的跳过一个属性的设置,但又不会再代码上留下空白,一眼看过,就知道跳过了那些属性,以后要补上这些跳过的属性也非常的方便。