2012-04-06 47 views
46

tôi đã tự hỏi điều gì sẽ là cách tốt nhất để thực hiện một điều kiện .When trong một giao diện thông thạo sử dụng phương pháp chaining trong một đối tượng Builder?Conditional Builder Phương pháp Chaining thạo Interface

Ví dụ thế nào tôi sẽ thực hiện .WithSkill().When() phương pháp trong ví dụ sau:

var level = 5; 

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

Cập nhật - Một giải pháp mẫu có thể được tìm thấy here.

Trả lời

70

những gì tôi muốn làm là có NinjaBuilder giữ hoạt động như một danh sách các đại biểu, chứ không phải áp dụng chúng, và chỉ áp dụng chúng khi .Build được gọi. Điều này sẽ cho phép bạn đặt chúng có điều kiện:

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; 
    } 
} 

Tất nhiên, điều này giả định rằng điều kiện không đổi tại thời điểm tạo người tạo. Nếu bạn muốn làm cho nó không liên tục, bạn có thể làm một cái gì đó giống như thay vì điều này:

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

Nếu bạn muốn When được hơi nhiều trình biên dịch kiểm tra, bạn có thể làm builderActions bảo vệ và làm điều gì đó như thế này:

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; 
    } 
} 

và có các hoạt động ban đầu trả về một ConditionalNinjaBuilder:

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

Bằng cách đó bạn chỉ có thể gọi .When sau khi cuộc gọi đầu tiên ing phương pháp khác. Điều này có thêm lợi thế/biến chứng của khả năng cho phép điều kiện lồng nhau/phức hợp, quá. Yikes.

+2

Lưu ý rằng bây giờ bạn đưa ra giả định rõ ràng về thời điểm bạn có thể sử dụng 'Khi' - chỉ ngay sau điều kiện của bạn. Bạn không thực thi điều này, vì vậy có thể dễ xảy ra lỗi. Ngoài ra chữ ký phương thức hiện tại của bạn là sai - mỗi chữ ký sẽ trả về một 'NinjaBuilder', nếu không thì đây không phải là giao diện thông thạo – BrokenGlass

+0

Sửa lỗi phương thức sigs. Tôi sẽ có một đâm vào làm cho nó rõ ràng. –

+0

Hãy cho tôi biết nó đi như thế nào - Tôi đã sử dụng các giao diện khác nhau (và các phương thức mở rộng tương ứng) để thực thi thứ tự trong quá khứ, tôi rất vui khi thấy một thứ gì đó thanh lịch hơn – BrokenGlass

3

Bạn có thể có một tham số tùy chọn có điều kiện trong phương pháp của bạn đó là true theo mặc định:

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

này tất nhiên sẽ có rất cụ thể cho các WithSkill phương pháp:

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

Bạn có thể thêm nó với các phương pháp khác mà bạn muốn có điều kiện.

Một lựa chọn khác là phải có một phương pháp mà làm tổ những phần điều kiện của người xây dựng:

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

Sau đó, bạn có thể viết nó như thế này:

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

Hoặc như thế này:

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

Điều này chung chung hơn và có thể được sử dụng với bất kỳ phương pháp nào của trình tạo.

Bạn thậm chí có thể thêm một tùy chọn "khác":

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

Hoặc, như một "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 ... 

Đây là khóa học một cách để tạo ra "nếu" phát biểu như các cuộc gọi phương pháp. Các cách khác cũng có thể làm việc:

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

Trong trường hợp này, những người xây dựng giữ theo dõi xem nó nên bỏ qua bất kỳ cuộc gọi phương pháp được thực hiện trong một bối cảnh "có điều kiện" nếu điều kiện là sai. When sẽ nhập ngữ cảnh, End sẽ thoát khỏi ngữ cảnh đó. Bạn cũng có thể có một cuộc gọi Otherwise() để đánh dấu ngữ cảnh "khác". Điều thú vị đủ, bạn cũng có thể bao gồm các báo cáo khác như thế này, giống như vòng:

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

Trong trường hợp này, các cuộc gọi được thực hiện trong "vòng lặp" bối cảnh phải được ghi và phát lại các số mong muốn lần khi End được gọi là .

Vì vậy, ngữ cảnh là một loại trạng thái trạng thái người xây dựng có thể ở; họ thay đổi cách nó hoạt động. Bạn cũng có thể lồng các bối cảnh, sử dụng một ngăn xếp để theo dõi chúng. Và bạn nên kiểm tra xem cuộc gọi nhất định có hợp lệ ở một số bang và có thể ném ngoại lệ nếu không.

5

Bạn có thể xem xét viết phiên bản quá tải của Với, và trong lần thứ hai, phải mất một trường hợp như một cuộc tranh cãi:

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

Tất nhiên, điều này được khẳng định dựa trên quan điểm cho rằng bạn đang đi để viết đâu như một đối tượng riêng biệt hoàn toàn, mà chủ yếu trông như thế này:

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

Tôi có giải pháp để giao diện chuỗi; vấn đề duy nhất với giải pháp của tôi là nó phát triển theo độ phức tạp (quy mô) với mọi phương pháp mới mà bạn muốn hỗ trợ. Nhưng, nó làm cho một API thực sự tuyệt vời cho người dùng.

Hãy để chúng tôi xem xét rằng bạn có 3 phương pháp, A, B và C và bạn muốn sử dụng chúng trong một chuỗi.

Hãy để chúng tôi cũng xem xét rằng bạn không muốn gọi bất kỳ phương thức nào nhiều lần.

ví dụ:

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

Điều này có thể được thực hiện với một số awesomeness nghiêm trọng:

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> { } 

Và sau đó, trộn này với awesomeness Chris Shain để sử dụng một ngăn xếp của các hành động!

Tôi quyết định triển khai. Lưu ý rằng bạn không thể gọi bất kỳ phương thức nào hai lần ngay bây giờ bằng giải pháp chuỗi này. Tôi đặt phương thức When của bạn làm phương pháp mở rộng.

Đây là mã gọi:

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

Đây là Ninja và kỹ năng lớp học của tôi:

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 
} 

Đây là lớp 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; 
    } 
} 

Và phần còn lại của này mã chỉ để thực hiện chuyển đổi và cuộc gọi hoạt động:

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

Điều này thật tuyệt vời, đặc biệt nếu được kết hợp với nội dung được viết cho jOOQ tại http://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/ trong đó cho thấy cách thực hiện bất kỳ ngôn ngữ thông thường nào bằng cách sử dụng giao diện. Lưu ý rằng bạn không cần sự bùng nổ giao diện này, bạn chỉ cần một giao diện cho mỗi lần chuyển tiếp trong máy trạng thái được thể hiện bằng ngôn ngữ thông thường của bạn. –

Các vấn đề liên quan