2012-04-06 15 views
46

मैं सोच रहा था क्या एक धाराप्रवाह इंटरफ़ेसविधि एक Builder वस्तु में चेनिंग का उपयोग करने में एक .When हालत लागू करने के लिए सबसे अच्छा तरीका क्या होगा?सशर्त बिल्डर विधि श्रृंखलन Fluent इंटरफ़ेस

उदाहरण है कि कैसे मैं निम्न उदाहरण में .WithSkill() और .When() तरीकों लागू करेगा के लिए:

var level = 5; 

var ninja = NinjaBuilder 
    .CreateNinja() 
    .Named("Ninja Boy") 
    .AtLevel(level) 
    .WithShurikens(10) 
    .WithSkill(Skill.HideInShadows) 
     .When(level > 3) 
    .Build() 

अद्यतन - एक नमूना समाधान here पाया जा सकता है।

उत्तर

70

मुझे क्या होता NinjaBuilder बल्कि उन्हें लागू करने से, प्रतिनिधियों की एक सूची के रूप में संचालन रखने के लिए, और जब .Build कहा जाता है केवल उन्हें लागू है। यह आप उन्हें सशर्त बनाने के लिए अनुमति होगी:

public class NinjaBuilder { 
    List<Action<Ninja>> builderActions = new List<Action<Ninja>>(); 

    public Ninja Build() { 
     var ninja = new Ninja(); 
     builderActions.ForEach(ba => ba(ninja)); 
     return ninja; 
    } 

    public NinjaBuilder WithShurikens(int numShirukens) { 
     builderActions.Add(n=>n.Shirukens = numShirukens); 
     return this; 
    } 

    public NinjaBuilder When(Boolean condition) { 
     if (!condition) // If the condition is not met, remove the last action 
      builderActions.Remove(builderActions.Length - 1); 
     return this; 
    } 
} 
बेशक

, इस मानता है कि हालत बिल्डर निर्माण के समय स्थिर है। आप इसे गैर निरंतर बनाना चाहते हैं, तो आप इस बजाय की तरह कुछ कर सकता है:

public NinjaBuilder When(Func<Boolean> condition) { 
     var oldAction = builderActions[builderActions.Length - 1]; 
     builderActions[builderActions.Length - 1] = n => condition() ? oldAction(n) : n; 
     return this; 
    } 

आप When कुछ और अधिक संकलक जाँच की जा चाहते हैं, आप builderActions संरक्षित बनाने के लिए और कुछ इस तरह कर सकते हैं:

public class ConditionalNinjaBuilder : NinjaBuilder { 
    public ConditionalNinjaBuilder(NinjaBuilder wrappedBuilder) {    
     // Since someone might call .WithShirukens on the wrapping 
     // builder directly, we should make sure that our actions 
     // list is the same instance as the one in our wrapped builder 
     builderActions = wrappedBuilder.builderActions; 
    } 

    public ConditionalNinjaBuilder When(Func<Boolean> condition) { 
     var oldAction = builderActions[builderActions.Length - 1]; 
     builderActions[builderActions.Length - 1] = n => condition() ? oldAction(n) : n; 
     return this; 
    } 
} 

public ConditionalNinjaBuilder WithShurikens(int numShirukens) { 
     builderActions.Add(n=>n.Shirukens = numShirukens); 
     return new ConditionalNinjaBuilder(this); 
    } 

इस तरह आप केवल पहली कॉल के बाद .When कॉल कर सकते हैं:

और मूल संचालन एक ConditionalNinjaBuilder वापसी एक और तरीका आईएनजी। इसमें संभावित रूप से नेस्टेड/मिश्रित सशर्तों की अनुमति देने का अतिरिक्त लाभ/जटिलता भी है। ओह।

+2

ध्यान दें कि अब आप स्पष्ट रूप से धारणा करते हैं जब आप 'कब' का उपयोग कर सकते हैं - केवल आपकी हालत के ठीक बाद। आप इसे लागू नहीं करते हैं, इसलिए त्रुटि-प्रवण हो सकता है। इसके अलावा आपके वर्तमान विधि हस्ताक्षर गलत हैं - प्रत्येक को 'निंजाबिल्डर' वापस करना चाहिए, अन्यथा यह एक धाराप्रवाह इंटरफेस नहीं है – BrokenGlass

+0

विधि सिग फिक्स्ड। मैं इसे स्पष्ट करने के लिए एक झुकाव होगा। –

+0

मुझे बताएं कि यह कैसे जाता है - मैंने अतीत में आदेश को लागू करने के लिए अलग-अलग इंटरफेस (और इसी तरह के विस्तार विधियों) का उपयोग किया है, मुझे कुछ और सुरुचिपूर्ण – BrokenGlass

3

आप अपने विधि में एक सशर्त वैकल्पिक पैरामीटर है कि है true डिफ़ॉल्ट रूप से हो सकता है:

public NinjaBuilder WithSkill(Skill skill, bool when = true) { 
    if (!when) return this; 
    // ... 
} 

आप इसे जोड़ सकते हैं:

.WithSkill(Skill.HideInShadows, when: level > 3) 

निश्चित रूप से हो जाएगा ताकि WithSkill विधि करने के लिए बहुत विशिष्ट अन्य विधियों के लिए जो आप सशर्त भी बनना चाहते हैं।

.When(level > 3, _=>_ 
    .WithSkill(Skill.HideInShadows) 
) 
:

public NinjaBuilder When(bool condition, Action<NinjaBuilder> then) { 
    if (condition) then(this); 
    return this; 
} 

तो फिर तुम इस तरह लिख सकते हैं: इस तरह

.When(level > 3, 
    then: _ => _.WithSkill(Skill.HideInShadows)) 

या

एक अन्य विकल्प के लिए एक विधि है कि बिल्डर की सशर्त भागों के घोंसले होते ही करने के लिए है

यह अधिक सामान्य है और निर्माता के किसी भी तरीके से इसका उपयोग किया जा सकता है।

तुम भी एक वैकल्पिक "और" जोड़ सकते हैं:

public NinjaBuilder When(bool condition, Action<NinjaBuilder> then, Action<NinjaBuilder> otherwise = null) { 
    if (condition) { 
    then(this); 
    } 
    else if (otherwise != null) { 
    otherwise(this); 
    } 
    return this; 
} 

या, एक "mixin" के रूप में:

public interface MBuilder {} 
public static class BuilderExtensions { 
    public static TBuilder When<TBuilder>(this TBuilder self, bool condition, Action<TBuilder> then, Action<TBuilder> otherwise = null) 
    where TBuilder : MBuilder 
    { 
    if (condition) { 
     then(self); 
    } 
    else if (otherwise != null) { 
     otherwise(self); 
    } 
    return self; 
    } 
} 

public class NinjaBuilder : MBuilder ... 

यह "अगर" विधि कॉल के रूप में बयान बनाने के लिए एक तरह से निश्चित रूप से है। अन्य तरीके भी काम कर सकता था:

.When(level > 3) // enter "conditional" context 
    .WithSkill(Skill.HideInShadows) 
.End() // exit "conditional" context 

इस मामले में, बिल्डर ट्रैक चाहे वह किसी भी विधि कॉल है कि एक "सशर्त" संदर्भ में किया जाता है अगर हालत झूठी है अनदेखा कर देना चाहिए रहता है। When संदर्भ दर्ज करेगा, End इसे बाहर निकलेंगा। "Else" संदर्भ को चिह्नित करने के लिए आपके पास Otherwise() कॉल भी हो सकता है। दिलचस्प बात यह है कि आप भी इस तरह अन्य बयान, छोरों की तरह कवर कर सकता:

.Do(times: 10) // add 10 shurikens 
    .AddShuriken() 
.End() 

इस मामले में, "लूप" संदर्भ में किए गए कॉल रिकॉर्ड किया जाना चाहिए और खेला वापस बार की वांछित संख्या जब End कहा जाता है ।

तो, संदर्भ राज्य एक प्रकार का निर्माता हो सकता है; वे बदलते हैं कि यह कैसे काम करता है। आप ट्रैक रखने के लिए एक ढेर का उपयोग करके, संदर्भों को घोंसला भी कर सकते हैं। और आपको यह जांचना चाहिए कि कुछ राज्यों में कुछ कॉल मान्य हैं या नहीं, अगर वे नहीं हैं तो अपवाद फेंक दें।

5

आप कर सकते थे के साथ की अतिभारित संस्करण लिखने पर विचार, और दूसरे में, एक तर्क के रूप में एक कहाँ ले:

var level = 5; 
var ninja = NinjaBuilder  
    .CreateNinja() 
    .Named("Ninja Boy") 
    .AtLevel(level) 
    .WithShurikens(10) 
    .WithSkill(Skill.HideInShadows, Where.Level(l => l > 3)) 
    .Build() 
बेशक

, इस धारणा है कि आप कहाँ के रूप में लिखने के लिए जा रहे हैं पर प्रतिपादित है एक अलग वस्तु पूरी तरह से, कि अनिवार्य रूप से इस तरह दिखता है:

public sealed static class Where 
{ 
    public bool Defense (Func<int, bool> predicate) { return predicate(); } 
    public bool Dodge (Func<int, bool> predicate) { return predicate(); } 
    public bool Level (Func<int, bool> predicate) { return predicate(); } 

} 
8

मेरे पास इंटरफेस चेनिंग का समाधान है; मेरे समाधान के साथ एकमात्र समस्या यह है कि यह हर नई विधि के साथ जटिलता (स्केल) में बढ़ता है जिसे आप समर्थन देना चाहते हैं। लेकिन, यह उपयोगकर्ता के लिए वास्तव में एक शानदार एपीआई बनाता है।

आइए मान लें कि आपके पास 3 विधियां, ए, बी, और सी हैं, और आप उन्हें श्रृंखला में उपयोग करना चाहते हैं।

आइए हम यह भी मान लें कि आप किसी भी विधि को एक से अधिक बार कॉल करने में सक्षम नहीं होना चाहते हैं।

उदा।

new Builder().A().B().C(); // OK 
new Builder().A().B().A(); // Not OK 

यह कुछ गंभीर awesomeness के साथ पूरा किया जा सकता है:

public class Builder : A<Not_A>, B<Not_B>, C<Not_C>, Not_A, Not_B, Not_C, Not_AB, Not_BC, Not_AC, Empty 
{ 
    Not_AB A<Not_AB>.A() { return (Not_AB)A(); } 
    Not_AC A<Not_AC>.A() { return (Not_AC)A(); } 
    Empty A<Empty>.A() { return (Empty)A(); } 
    public Not_A A() 
    { 
    return (Not_A)this; 
    } 

    Not_AB B<Not_AB>.B() { return (Not_AB)B(); } 
    Not_BC B<Not_BC>.B() { return (Not_BC)B(); } 
    Empty B<Empty>.B() { return (Empty)B(); } 
    public Not_B B() 
    { 
    return (Not_B)this; 
    } 

    Not_AC C<Not_AC>.C() { return (Not_AC)C(); } 
    Not_BC C<Not_BC>.C() { return (Not_BC)C(); } 
    Empty C<Empty>.C() { return (Empty)C(); } 
    public Not_C C() 
    { 
    return (Not_C)this; 
    } 
} 

public interface Empty { } 

public interface A<TRemainder> { TRemainder A(); } 
public interface B<TRemainder> { TRemainder B(); } 
public interface C<TRemainder> { TRemainder C(); } 

public interface Not_A : B<Not_AB>, C<Not_AC> { } 
public interface Not_B : A<Not_AB>, C<Not_BC> { } 
public interface Not_C : A<Not_AC>, B<Not_BC> { } 

public interface Not_AB : C<Empty> { } 
public interface Not_BC : A<Empty> { } 
public interface Not_AC : B<Empty> { } 

और फिर, कार्रवाई के ढेर का उपयोग करने के क्रिस Shain की प्रभावशीलता के साथ इस मिश्रण!

मैंने इसे लागू करने का निर्णय लिया। ध्यान दें कि आप इस श्रृंखला समाधान के साथ अब दो बार किसी भी विधि को कॉल नहीं कर सकते हैं। मैंने आपकी When विधि को विस्तार विधि के रूप में रखा है।

यहाँ बुला कोड है:

int level = 5; 
    var ninja = NinjaBuilder 
     .CreateNinja() 
     .Named("Ninja Boy") 
     .AtLevel(level) 
     .WithShurikens(10) 
     .WithSkill(Skill.HideInShadows) 
      .When(n => n.Level > 3) 
     .Build(); 

यहाँ है मेरी निंजा और कौशल कक्षाएं:

public class Ninja 
{ 
    public string Name { get; set; } 
    public int Level { get; set; } 
    public int Shurikens { get; set; } 
    public Skill Skill { get; set; } 
} 

public enum Skill 
{ 
    None = 1, 
    HideInShadows 
} 

यह NinjaBuilder वर्ग है:

public class NinjaBuilder : NinjaBuilder_Sans_Named 
{ 
    public static NinjaBuilder CreateNinja() { return new NinjaBuilder(); } 
    public Stack<Action<Ninja>> _buildActions; 

    public NinjaBuilder() 
    { 
    _buildActions = new Stack<Action<Ninja>>(); 
    } 

    public override Ninja Build() 
    { 
    var ninja = new Ninja(); 
    while (_buildActions.Count > 0) 
    { 
     _buildActions.Pop()(ninja); 
    } 

    return ninja; 
    } 

    public override void AddCondition(Func<Ninja, bool> condition) 
    { 
    if (_buildActions.Count == 0) 
     return; 

    var top = _buildActions.Pop(); 
    _buildActions.Push(n => { if (condition(n)) { top(n); } }); 
    } 

    public override Sans_Named_NinjaBuilder Named(string name) 
    { 
    _buildActions.Push(n => n.Name = name); 
    return this; 
    } 

    public override Sans_AtLevel_NinjaBuilder AtLevel(int level) 
    { 
    _buildActions.Push(n => n.Level = level); 
    return this; 
    } 

    public override Sans_WithShurikens_NinjaBuilder WithShurikens(int shurikenCount) 
    { 
    _buildActions.Push(n => n.Shurikens = shurikenCount); 
    return this; 
    } 

    public override Sans_WithSkill_NinjaBuilder WithSkill(Skill skillType) 
    { 
    _buildActions.Push(n => n.Skill = skillType); 
    return this; 
    } 
} 

और इस के बाकी रूपांतरण करने और कॉल करने के लिए कोड सिर्फ ओवरहेड है:

public abstract class NinjaBuilderBase : 
    EmptyNinjaBuilder, 
    Named_NinjaBuilder<Sans_Named_NinjaBuilder>, 
    AtLevel_NinjaBuilder<Sans_AtLevel_NinjaBuilder>, 
    WithShurikens_NinjaBuilder<Sans_WithShurikens_NinjaBuilder>, 
    WithSkill_NinjaBuilder<Sans_WithSkill_NinjaBuilder> 
{ 
    public abstract void AddCondition(Func<Ninja, bool> condition); 
    public abstract Ninja Build(); 

    public abstract Sans_WithSkill_NinjaBuilder WithSkill(Skill skillType); 
    public abstract Sans_WithShurikens_NinjaBuilder WithShurikens(int shurikenCount); 
    public abstract Sans_AtLevel_NinjaBuilder AtLevel(int level); 
    public abstract Sans_Named_NinjaBuilder Named(string name); 
} 

public abstract class NinjaBuilder_Sans_WithSkill : NinjaBuilderBase, 
    Sans_WithSkill_NinjaBuilder 
{ 
    Sans_Named_WithSkill_NinjaBuilder Named_NinjaBuilder<Sans_Named_WithSkill_NinjaBuilder>.Named(string name) { return (Sans_Named_WithSkill_NinjaBuilder)Named(name); } 
    Sans_AtLevel_WithSkill_NinjaBuilder AtLevel_NinjaBuilder<Sans_AtLevel_WithSkill_NinjaBuilder>.AtLevel(int level) { return (Sans_AtLevel_WithSkill_NinjaBuilder)AtLevel(level); } 
    Sans_WithShurikens_WithSkill_NinjaBuilder WithShurikens_NinjaBuilder<Sans_WithShurikens_WithSkill_NinjaBuilder>.WithShurikens(int shurikenCount) { return (Sans_WithShurikens_WithSkill_NinjaBuilder)WithShurikens(shurikenCount); } 
} 

public abstract class NinjaBuilder_Sans_WithShurikens : NinjaBuilder_Sans_WithSkill, 
    Sans_WithShurikens_NinjaBuilder, 
    Sans_WithShurikens_WithSkill_NinjaBuilder 
{ 
    Sans_Named_WithShurikens_WithSkill_NinjaBuilder Named_NinjaBuilder<Sans_Named_WithShurikens_WithSkill_NinjaBuilder>.Named(string name) { return (Sans_Named_WithShurikens_WithSkill_NinjaBuilder)Named(name); } 
    Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder AtLevel_NinjaBuilder<Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder>.AtLevel(int level) { return (Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder)AtLevel(level); } 
    Sans_Named_WithSkill_NinjaBuilder Named_NinjaBuilder<Sans_Named_WithSkill_NinjaBuilder>.Named(string name) { return (Sans_Named_WithSkill_NinjaBuilder)Named(name); } 
    Sans_AtLevel_WithShurikens_NinjaBuilder AtLevel_NinjaBuilder<Sans_AtLevel_WithShurikens_NinjaBuilder>.AtLevel(int level) { return (Sans_AtLevel_WithShurikens_NinjaBuilder)AtLevel(level); } 
    Sans_WithShurikens_WithSkill_NinjaBuilder WithSkill_NinjaBuilder<Sans_WithShurikens_WithSkill_NinjaBuilder>.WithSkill(Skill skillType) { return (Sans_WithShurikens_WithSkill_NinjaBuilder)WithSkill(skillType); } 
} 

public abstract class NinjaBuilder_Sans_AtLevel : NinjaBuilder_Sans_WithShurikens, 
    Sans_AtLevel_NinjaBuilder, 
    Sans_AtLevel_WithShurikens_NinjaBuilder, 
    Sans_AtLevel_WithSkill_NinjaBuilder, 
    Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder 
{ 
    EmptyNinjaBuilder Named_NinjaBuilder<EmptyNinjaBuilder>.Named(string name) { return Named(name); } 
    Sans_Named_AtLevel_WithSkill_NinjaBuilder Named_NinjaBuilder<Sans_Named_AtLevel_WithSkill_NinjaBuilder>.Named(string name) { return (Sans_Named_AtLevel_WithSkill_NinjaBuilder)Named(name); } 
    Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder WithShurikens_NinjaBuilder<Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder>.WithShurikens(int shurikenCount) { return (Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder)WithShurikens(shurikenCount); } 
    Sans_Named_AtLevel_WithShurikens_NinjaBuilder Named_NinjaBuilder<Sans_Named_AtLevel_WithShurikens_NinjaBuilder>.Named(string name) { return (Sans_Named_AtLevel_WithShurikens_NinjaBuilder)Named(name); } 
    Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder WithSkill_NinjaBuilder<Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder>.WithSkill(Skill skillType) { return (Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder)WithSkill(skillType); } 
    Sans_Named_AtLevel_NinjaBuilder Named_NinjaBuilder<Sans_Named_AtLevel_NinjaBuilder>.Named(string name) { return (Sans_Named_AtLevel_NinjaBuilder)Named(name); } 
    Sans_AtLevel_WithShurikens_NinjaBuilder WithShurikens_NinjaBuilder<Sans_AtLevel_WithShurikens_NinjaBuilder>.WithShurikens(int shurikenCount) { return (Sans_AtLevel_WithShurikens_NinjaBuilder)WithShurikens(shurikenCount); } 
    Sans_AtLevel_WithSkill_NinjaBuilder WithSkill_NinjaBuilder<Sans_AtLevel_WithSkill_NinjaBuilder>.WithSkill(Skill skillType) { return (Sans_AtLevel_WithSkill_NinjaBuilder)WithSkill(skillType); } 
} 

public abstract class NinjaBuilder_Sans_Named : NinjaBuilder_Sans_AtLevel, 
    Sans_Named_NinjaBuilder, 
    Sans_Named_AtLevel_NinjaBuilder, 
    Sans_Named_WithShurikens_NinjaBuilder, 
    Sans_Named_WithSkill_NinjaBuilder, 
    Sans_Named_WithShurikens_WithSkill_NinjaBuilder, 
    Sans_Named_AtLevel_WithSkill_NinjaBuilder, 
    Sans_Named_AtLevel_WithShurikens_NinjaBuilder 
{ 
    EmptyNinjaBuilder WithSkill_NinjaBuilder<EmptyNinjaBuilder>.WithSkill(Skill skillType) { return (EmptyNinjaBuilder)WithSkill(skillType); } 
    EmptyNinjaBuilder WithShurikens_NinjaBuilder<EmptyNinjaBuilder>.WithShurikens(int shurikenCount) { return (EmptyNinjaBuilder)WithShurikens(shurikenCount); } 
    EmptyNinjaBuilder AtLevel_NinjaBuilder<EmptyNinjaBuilder>.AtLevel(int level) { return (EmptyNinjaBuilder)AtLevel(level); } 
    Sans_Named_AtLevel_WithShurikens_NinjaBuilder AtLevel_NinjaBuilder<Sans_Named_AtLevel_WithShurikens_NinjaBuilder>.AtLevel(int level) { return (Sans_Named_AtLevel_WithShurikens_NinjaBuilder)AtLevel(level); } 
    Sans_Named_WithShurikens_WithSkill_NinjaBuilder WithShurikens_NinjaBuilder<Sans_Named_WithShurikens_WithSkill_NinjaBuilder>.WithShurikens(int shurikenCount) { return (Sans_Named_WithShurikens_WithSkill_NinjaBuilder)WithShurikens(shurikenCount); } 
    Sans_Named_WithShurikens_WithSkill_NinjaBuilder WithSkill_NinjaBuilder<Sans_Named_WithShurikens_WithSkill_NinjaBuilder>.WithSkill(Skill skillType) { return (Sans_Named_WithShurikens_WithSkill_NinjaBuilder)WithSkill(skillType); } 
    Sans_Named_AtLevel_WithShurikens_NinjaBuilder WithShurikens_NinjaBuilder<Sans_Named_AtLevel_WithShurikens_NinjaBuilder>.WithShurikens(int shurikenCount) { return (Sans_Named_AtLevel_WithShurikens_NinjaBuilder)WithShurikens(shurikenCount); } 
    Sans_Named_AtLevel_WithSkill_NinjaBuilder WithSkill_NinjaBuilder<Sans_Named_AtLevel_WithSkill_NinjaBuilder>.WithSkill(Skill skillType) { return (Sans_Named_AtLevel_WithSkill_NinjaBuilder)WithSkill(skillType); } 
    Sans_Named_AtLevel_NinjaBuilder AtLevel_NinjaBuilder<Sans_Named_AtLevel_NinjaBuilder>.AtLevel(int level) { return (Sans_Named_AtLevel_NinjaBuilder)AtLevel(level); } 
    Sans_Named_WithShurikens_NinjaBuilder WithShurikens_NinjaBuilder<Sans_Named_WithShurikens_NinjaBuilder>.WithShurikens(int shurikenCount) { return (Sans_Named_WithShurikens_NinjaBuilder)WithShurikens(shurikenCount); } 
    Sans_Named_WithSkill_NinjaBuilder WithSkill_NinjaBuilder<Sans_Named_WithSkill_NinjaBuilder>.WithSkill(Skill skillType) { return (Sans_Named_WithSkill_NinjaBuilder)WithSkill(skillType); } 
} 

public static class NinjaBuilderExtension 
{ 
    public static TBuilderLevel When<TBuilderLevel>(this TBuilderLevel ths, Func<Ninja, bool> condition) where TBuilderLevel : EmptyNinjaBuilder 
    { 
    ths.AddCondition(condition); 
    return ths; 
    } 
} 

public interface EmptyNinjaBuilder { void AddCondition(Func<Ninja, bool> condition); Ninja Build(); } 

public interface Named_NinjaBuilder<TRemainder> { TRemainder Named(string name); } 
public interface AtLevel_NinjaBuilder<TRemainder> { TRemainder AtLevel(int level);} 
public interface WithShurikens_NinjaBuilder<TRemainder> { TRemainder WithShurikens(int shurikenCount); } 
public interface WithSkill_NinjaBuilder<TRemainder> { TRemainder WithSkill(Skill skillType); } 

// level one reductions 
public interface Sans_Named_NinjaBuilder : 
    AtLevel_NinjaBuilder<Sans_Named_AtLevel_NinjaBuilder>, 
    WithShurikens_NinjaBuilder<Sans_Named_WithShurikens_NinjaBuilder>, 
    WithSkill_NinjaBuilder<Sans_Named_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 
public interface Sans_AtLevel_NinjaBuilder : 
    Named_NinjaBuilder<Sans_Named_AtLevel_NinjaBuilder>, 
    WithShurikens_NinjaBuilder<Sans_AtLevel_WithShurikens_NinjaBuilder>, 
    WithSkill_NinjaBuilder<Sans_AtLevel_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 
public interface Sans_WithShurikens_NinjaBuilder : 
    Named_NinjaBuilder<Sans_Named_WithSkill_NinjaBuilder>, 
    AtLevel_NinjaBuilder<Sans_AtLevel_WithShurikens_NinjaBuilder>, 
    WithSkill_NinjaBuilder<Sans_WithShurikens_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 
public interface Sans_WithSkill_NinjaBuilder : 
    Named_NinjaBuilder<Sans_Named_WithSkill_NinjaBuilder>, 
    AtLevel_NinjaBuilder<Sans_AtLevel_WithSkill_NinjaBuilder>, 
    WithShurikens_NinjaBuilder<Sans_WithShurikens_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 

// level two reductions 
// Named 
public interface Sans_Named_AtLevel_NinjaBuilder : 
    WithShurikens_NinjaBuilder<Sans_Named_AtLevel_WithShurikens_NinjaBuilder>, 
    WithSkill_NinjaBuilder<Sans_Named_AtLevel_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 
public interface Sans_Named_WithShurikens_NinjaBuilder : 
    AtLevel_NinjaBuilder<Sans_Named_AtLevel_WithShurikens_NinjaBuilder>, 
    WithSkill_NinjaBuilder<Sans_Named_WithShurikens_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 
public interface Sans_Named_WithSkill_NinjaBuilder : 
    AtLevel_NinjaBuilder<Sans_Named_AtLevel_WithShurikens_NinjaBuilder>, 
    WithShurikens_NinjaBuilder<Sans_Named_WithShurikens_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 
// AtLevel 
public interface Sans_AtLevel_WithShurikens_NinjaBuilder : 
    Named_NinjaBuilder<Sans_Named_AtLevel_WithShurikens_NinjaBuilder>, 
    WithSkill_NinjaBuilder<Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 
public interface Sans_AtLevel_WithSkill_NinjaBuilder : 
    Named_NinjaBuilder<Sans_Named_AtLevel_WithSkill_NinjaBuilder>, 
    WithShurikens_NinjaBuilder<Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 
// WithShurikens 
public interface Sans_WithShurikens_WithSkill_NinjaBuilder : 
    Named_NinjaBuilder<Sans_Named_WithShurikens_WithSkill_NinjaBuilder>, 
    AtLevel_NinjaBuilder<Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder>, 
    EmptyNinjaBuilder { } 

// level three reductions 
// Named 
public interface Sans_AtLevel_WithShurikens_WithSkill_NinjaBuilder : 
    Named_NinjaBuilder<EmptyNinjaBuilder>, 
    EmptyNinjaBuilder { } 
// AtLevel 
public interface Sans_Named_WithShurikens_WithSkill_NinjaBuilder : 
    AtLevel_NinjaBuilder<EmptyNinjaBuilder>, 
    EmptyNinjaBuilder { } 
// WithShurikens 
public interface Sans_Named_AtLevel_WithSkill_NinjaBuilder : 
    WithShurikens_NinjaBuilder<EmptyNinjaBuilder>, 
    EmptyNinjaBuilder { } 
// WithSkill 
public interface Sans_Named_AtLevel_WithShurikens_NinjaBuilder : 
    WithSkill_NinjaBuilder<EmptyNinjaBuilder>, 
    EmptyNinjaBuilder { } 
+0

यह बहुत ही बढ़िया है, खासकर यदि jOOQ.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/ पर jOOQ के लिए जो लिखा गया था, उससे जुड़ा हुआ है जो दिखाता है कि कैसे इंटरफेस का उपयोग कर किसी भी नियमित भाषा को लागू करें। ध्यान दें कि आपको इस इंटरफ़ेस विस्फोट की आवश्यकता नहीं है, आपको केवल अपनी नियमित भाषा द्वारा प्रदर्शित राज्य मशीन में प्रत्येक संक्रमण के लिए एक इंटरफ़ेस की आवश्यकता है। –

संबंधित मुद्दे