2016-04-26 8 views
8

Zobacz poniżej kodów:Jak stworzyć płynny interfejs w języku C# z pewnymi ograniczeniami dla niektórych metod?

new ConditionCreator() 
     .Add() 
      .Or() 
     .Add() 
      .And() 
     .Add() 

Chcę utworzyć płynny interfejs dla tego Ale muszę, po add() metoda dewelopera zobaczyć Only lub() lub I() i po jednym z nich , zobacz Tylko metoda Add().

więc nikt nie może napisać kod jak:

new ConditionCreator() 
      .Add() 
      .Add() 
      .Add() 
      .Or() 
      .And() 
      .Add() 
      .And() 
      .And() 

Chcę mieć ograniczenia na niektóre metody mogą przyjąć specjalne metody i itp mogę napisać wszystkie metody w jednej klasie i powrót to dla każdego jeden, ale to nie jest odpowiednie !!!

Proszę, poprowadź mnie Jak napisać klasę Advanced Fluent Interface.

+1

spojrzeć na kodzie dla FluentAssertions: https://github.com/dennisdoomen/FluentAssertions mogliby już masz to, czego potrzebujesz. – trailmax

+1

Twoja zaakceptowana odpowiedź nadal może uwzględniać 'new ConditionCreator() .Add(). Lub(). Oraz(). Oraz(). I()'. Czy tego właśnie chciałeś, czy też źle zrozumiałem twoje pytanie. – Nkosi

+0

Zobacz moją zaktualizowaną odpowiedź, aby uzyskać więcej informacji o tym, jak rozwiązać to poprawnie. – Macke

Odpowiedz

1

rozważyć powrót interfejs, który zawiera tylko And() i Or(). Na przykład:

public class ConditionCreator : IFluentAndOr 
{ 
    public IFluentAndOr And() { ... } 
    public IFluentAndOr Or() { ... } 
} 

public interface IFluentAndOr 
{ 
    IFluentAndOr And(); 
    IFluentAndOr Or(); 
} 
+4

jak to rozwiązuje pytanie? –

3

Aby ograniczyć liczbę rzeczy, musisz utworzyć i zwrócić jeden (prawdopodobnie z kilku) obiekt "konstruktora", który może wykonywać operacje specjalne, zachowując odniesienie do głównej klasy.

public class ConditionCreator 
{ 
    public ConditionCreator() { ... } 

    public SubConditionCreator Add() { ...; return new SubConditionCreator(this); } 

    internal ConditionCreator OnAdd() { ...; return this; }; 
    internal ConditionCreator OnOr() { ...; return this; }; 
} 

public class SubConditionCreator 
{ 
    private ConditionCreator _creator; 

    internal SubConditionCreator(ConditionCreator c) { _creator = c; } 

    public ConditionCreator And() { return _creator.OnAdd(); } 
    public ConditionCreator Or() { return _creator.OnOr(); } 
} 

Użyj dostępu wewnętrznego, aby ograniczyć użycie.

Aby uniknąć tworzenia śmieci przechowywać ref SubConditionCreator w głównej klasy

2

Nie istnieje prawdziwa łatwa droga, którą znam, aby rozwiązać ten problem. Być może szablon T4 może pomóc, ale do tej pory zawsze musiałem budować drzewo decyzyjne, z jawnym interfejsem w każdym węźle. Na przykład; Załóżmy drzewo decyzja jest nieskończoną pętlę, a następnie (realizowane odpowiednio):

interface IStart<T> 
{ 
    IAndOr Add(); 
    T End(); 
} 
interface IAndOr<T> 
{ 
    IStart<T> And(); 
    IStart<T> Or(); 
} 

To staje się trudne, jeśli chcesz skończoną pętlę; powiedzieć zero do dwóch dodaje:

interface IStart<T> : IFinish<T> 
{ 
    IAndOrFirst<T> Add(); 
} 

interface IAndOrFirst<T> 
{ 
    ISecond<T> And(); 
    ISecond<T> Or(); 
} 

interface ISecond<T> : IFinish<T> 
{ 
    IAndOrSecond<T> Add(); 
} 

interface IAndOrSecond <T> 
{ 
    IFinish<T> And(); 
    IFinish<T> Or(); 
}  
interface IFinish<T> 
{  
    T End(); 
} 

można (jawnie) wdrożyć je w jednej klasie, który działa jako machiny państwowej:

class ConditionCreator <T> : IStart<T>, IFinish<T>, IAndOrFirst<T>, IAndOrSecond<T> {...} 

gdzie można by powrócić this dla Add()And()Or() i utrzymania te zmiany stanu i kolejność.

Mam nadzieję, że niektóre odpowiedzi na to pytanie z lepszym sposobem, który ręcznie wypisuje każdy węzeł.

0
  public class DoEqual 
       { 

       } 
       public interface ICanAddWhereValue 
       { 
        ICanAddWhereOrRun IsEqualTo(object value); 
        ICanAddWhereOrRun IsNotEqualTo(object value); 
        IBothEqual BothEqual (object value); 
       } 

       public interface IBothEqual 
       { 
        DoEqual Excute(); 
       } 


       public interface ICanAddWhereOrRun 
       { 
        ICanAddWhereValue Where(string columnName); 
        bool RunNow(); 
        DoEqual Excute(); 
       } 

      public interface ICanAddCondition 
       { 
        ICanAddWhereValue Where(string columnName); 
        bool AllRows(); 
       } 

     namespace BuildAFluentInterface 
     { 
      public class WhereCondition 
      { 
       public enum ComparisonMethod 
       { 
        EqualTo, 
        NotEqualTo 
       } 

       public string ColumnName { get; private set; } 
       public ComparisonMethod Comparator { get; private set; } 
       public object Value { get; private set; } 

       public WhereCondition(string columnName, ComparisonMethod comparator, object value) 
       { 
        ColumnName = columnName; 
        Comparator = comparator; 
        Value = value; 
       } 
      } 
     } 

    using System.Collections.Generic; 

    namespace BuildAFluentInterface 
    { 
     public class DeleteQueryWithoutGrammar 
     { 
      private readonly string _tableName; 
      private readonly List<WhereCondition> _whereConditions = new List<WhereCondition>(); 

      private string _currentWhereConditionColumn; 

      // Private constructor, to force object instantiation from the fluent method(s) 
      private DeleteQueryWithoutGrammar(string tableName) 
      { 
       _tableName = tableName; 
      } 

      #region Initiating Method(s) 

      public static DeleteQueryWithoutGrammar DeleteRowsFrom(string tableName) 
      { 
       return new DeleteQueryWithoutGrammar(tableName); 
      } 

      #endregion 

      #region Chaining Method(s) 

      public DeleteQueryWithoutGrammar Where(string columnName) 
      { 
       _currentWhereConditionColumn = columnName; 

       return this; 
      } 

      public DeleteQueryWithoutGrammar IsEqualTo(object value) 
      { 
       _whereConditions.Add(new WhereCondition(_currentWhereConditionColumn, WhereCondition.ComparisonMethod.EqualTo, value)); 

       return this; 
      } 

      public DeleteQueryWithoutGrammar IsNotEqualTo(object value) 
      { 
       _whereConditions.Add(new WhereCondition(_currentWhereConditionColumn, WhereCondition.ComparisonMethod.NotEqualTo, value)); 

       return this; 
      } 

      #endregion 

      #region Executing Method(s) 

      public void AllRows() 
      { 
       ExecuteThisQuery(); 
      } 

      public void RunNow() 
      { 
       ExecuteThisQuery(); 
      } 

      #endregion 

      private void ExecuteThisQuery() 
      { 
       // Code to build and execute the delete query 
      } 
     } 
    } 
<br> 
In Main Test with 
public class myclass 
{ 
private static void Main(string[] args) 
     { 
DoEqual x3 = 
       DeleteQueryWithGrammar.DeleteRowsFrom("Account") 
        .Where("Admin") 
        .IsNotEqualTo("Admin") 
        .Where("Admin") 
        .BothEqual("X") 
        .Excute(); 
} 
} 
0

To wydaje się działać.

public class ConditionCreator 
    { 
    private Decision decision; 

    public ConditionCreator() { decision = new Decision(this); } 
    public Decision Add() { return decision; } 

    public class Decision 
    { 
     private ConditionCreator creator; 

     public Decision(ConditionCreator creator) { this.creator = creator; } 
     public ConditionCreator And() { return creator; } 
     public ConditionCreator Or() { return creator; } 
     public Condition Create() { return new Condition(); } 
    } 
    } 

A ty teraz ogranicza się do wzorów, jak to podczas dokonywania połączeń:

 var condition = new ConditionCreator() 
     .Add() 
     .Or() 
     .Add() 
     .And() 
     .Add() 
     .Create(); 
+0

Teraz zdaję sobie sprawę, że to bardzo przypomina odpowiedź @ Macke'a. No cóż... –

Powiązane problemy