2015-10-22 50 views
1

我們的框架提供了某種「日誌」對象;這實際上代表了傳統C/C++代碼中的遺留結構。今天,我開始編寫一個幫助器類,它使用構建器模式來創建更現代化的方法來創建此類日誌對象。有沒有像「建造一次」的建設者?

但有一個問題,對此我不知道正確的答案是什麼:

基本上這些日誌對象有一些屬性是「必需的」;所以在構建器模式之後,您必須將這些參數指定爲新構建器類的ctor的參數。然後構建器有一些方法來配置「可選屬性」;當然還有一個方法「build()」,它會發出一個包含收集值彙總的日誌對象。

但現在我想知道:我應該關心人們是否會重新使用相同的構建器對象?所以,我應該有一個「reset()」方法來清除所有可選參數;或者阻止build()被多次調用? 還是不要擔心不是全部?

回答

1

我應該在意人們是否會重新使用相同的構建器對象?

那麼你想觀察副作用,但我認爲這就是你問的原因,因爲你知道人們/代碼會在構建器中留下垃圾。

所以,我應該有一個「reset()」方法來清除所有可選參數;

我認爲,如果你傳遞一個構建器,清理的責任應該在消費者(將構建器作爲輸入的函數或類)上。所以我們不會造成副作用。例如:

public class SomeClass { 
    public SomeClass(Log.Builder builder){ 
     builder.tag("SomeClass"); //bad, we caused a side effect 
           //someone class forgets to set the tag 
           //later, then they get this tag 
     log = builder.build(); 
    } 
} 

一個解決方案是提供一個拷貝構造函數:

public class SomeClass { 
    public SomeClass(Log.Builder builder){ 
     Log.Builder localBuilder = new Log.Builder(builder); //copy constructor being used. 
     localBuilder.tag("SomeClass"); //only applies to the local builder 
     log = localBuilder.build(); 
    } //builder is as it was before the call, no side effect 
} 

你甚至可以調用SomeClass一份副本,這樣你就不需要關心它是否被實現爲無副作用或不:

Log.Builder defaults = new Log.Builder(...whatever...).tag("notag"); 
new SomeClass(new Log.Builder(defaults)); 
new SomeClass2(new Log.Builder(defaults)); 

爲了進一步鎖定下來,你可以有一個接口Log.ReadOnlyBuilder它沒有制定者,是真的只用於建築或c好reating副本:

public class Log { 
    public interface ReadOnlyBuilder { 
     Builder copy(); 
     Log build(); 
    } 

    public static class Builder implements ReadOnlyBuilder { 
     Builder tag(String tag){ 
      ... 
     } 
    } 
} 

public class SomeClass { 
    public SomeClass(Log.ReadOnlyBuilder builder){ 
     log = builder.copy().tag("SomeClass").build(); 
    } //builder is as it was before the call, no side effect 
} 

我喜歡這一點,因爲責任是回到了消費者不會引起副作用,但它是強制執行,雖然類型和接口。另外如果他們不需要設置任何字段,他們可以只使用只讀構建器,我們不必爲了以防萬一。

P.S.我不認爲可選的和要求的是您想要決定要重置什麼和要設置什麼的劃分點。我認爲複製構造函數應該將構建器中的每個字段複製到新構建器。但是你可以自由地開發copy方法/構造函數,但是你喜歡。

2

無需重置,只需保持允許使用同一個構建器對象生成新對象即可。開發人員可以創建一個新的構建器,以避免重複使用之前設置的內容。此外,Twitter4j有這樣的事情(並且是開源的),如果你希望看到的事情應該如何工作(見http://twitter4j.org/en/configuration.html):

ConfigurationBuilder cb = new ConfigurationBuilder(); 
cb.setDebugEnabled(true) 
    .setOAuthConsumerKey("*********************") 
    .setOAuthConsumerSecret("******************************************") 
    .setOAuthAccessToken("**************************************************") 
    .setOAuthAccessTokenSecret("******************************************"); 
TwitterFactory tf = new TwitterFactory(cb.build()); 
Twitter twitter = tf.getInstance(); 
0

我在這些種情況,發現有用的建設者時是重複使用多次,並且存在一些剩餘數據重疊的可能性,即在構建器類中要創建未初始化的對象,並將初始化職責留給構建器實例。這樣,構建的對象不會關心(或知道)來自先前構建會話的垃圾剩餘量,並且如果它需要相同的可選數據,那麼構建器也知道重新初始化該數據。