2012-02-09 3 views
1

Я хочу реализовать шаблон команды. У меня есть следующее:Реализация шаблона команды и полиморфизма

public class State 
{ 
    public int Number { get; set; } 

    public void Execute(IAction action) 
    { 
     if (action.IsValid(this)) 
      action.Apply(this); 
    }    
} 

public interface IAction 
{ 
    bool IsValid(State state); 
    void Apply(State state); 
}  

public class ActionSet5IfZero : IAction 
{ 

    public bool IsValid(State state) 
    { 
     if (state.Number == 0) 
      return true; 
     else 
      return false; 
    } 

    public void Apply(State state) 
    { 
     state.Number = 5; 
    } 
} 

И программа:

static void Main(string[] args) 
{ 
    State s = new State(); 
    s.Execute(new ActionSet5IfZero()); 
} 

Это работает, как ожидалось. Моя проблема начинается, когда я хотел бы расширить государственный класс:

public class ExtendedState : State 
{ 
    public int Number2 { get; set; } 
} 

Теперь действие должно применить изменения на ExtendedState. Так я думал, я хотел бы создать расширенное действие, которое имеет две дополнительные функции, которые принимают ExtendedState в качестве параметра:

public class ExtendedActionSet5IfZero : IAction 
{ 

    public bool IsValid(State state) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Apply(State state) 
    { 
     throw new NotImplementedException(); 
    } 

    public bool IsValid(ExtendedState state) 
    { 
     if (state.Number == 0 && state.Number2 == 0) 
      return true; 
     else 
      return false; 
    } 

    public void Apply(ExtendedState state) 
    { 
     state.Number = 5; 
     state.Number2 = 5; 
    } 
} 

Это то, что я уже не нравится потому, что функции, которые реализуют интерфейс становятся лишними. Кроме того, мне нужно создать новую функцию Execute в моем ExtendedState, которая использует новый тип, а не IAction (иначе вызываемые функции не вызываются).

Уверен, что это может быть сделано с хорошим способом OO. Можете ли вы мне помочь? Цель состоит в том, чтобы создать расширяемый класс State и интерфейс IAction (возможно, даже общий, я не знаю), поэтому я могу расширить State, но остаюсь общей функциональностью без дополнительного кодирования.

ответ

0

Вы могли бы использовать дженерик:

interface IAction<TState> where TState: State 
{ 
    bool IsValid(TState state); 
    void Apply(TState state); 
} 
+1

Я пробовал это раньше. Проблема заключается в том, что я расширяю класс State и пытаюсь повторно использовать функцию Execute. Тип IAction не связан с IAction , и я получаю исключение. –

0

Как насчет добавления StateContainer в государство и действия:

public interface IStateContainer<TState, TAction> where TState : IState where TAction : IAction<TState> { 
    public TState State; 
    public void Execute(TAction action); 
} 

public interface IState { } 

public interface IAction<TState> where TState : IState { 
    bool IsValid(TState state); 
    void Apply(TState state); 
} 

Тогда исходные классы могут быть заменены:

public class ValidatingStateContainer<TState, TAction> : IStateContainer<TState, TAction> { 

    public ValidatingStateContainer(TState state) { 
     State = state; 
    } 

    public TState State { get; private set; } 

    public void Execute(TAction action) 
    { 
     if (action.IsValid(this)) 
      action.Apply(State); 
    } 
} 

public class ActionSet5IfZero : IAction<NumberState> 
{ 
    public boolean IsValid(NumberState state) 
    { 
     if (state.Number == 0) 
      return true; 
     else 
      return false; 
    } 

    public void Apply(NumberState state) 
    { 
     state.Number = 5; 
    } 
} 

public class ExtendedActionSet5IfZero : ActionSet5IfZero, IAction<TwoNumberState> 
{ 
    public boolean IsValid(TwoNumberState state) 
    { 
     if (base.IsValid(state) && state.Number2 == 0) 
      return true; 
     else 
      return false; 
    } 

    public void Apply(TwoNumberState state) 
    { 
     base.Apply(state); 
     state.Number2 = 5; 
    } 
} 

public class NumberState : IState { 
    public int Number { get; set; } 
} 

public class TwoNumberState : NumberState { 
    public int Number2 { get; set; } 
} 
1

Вы могли бы добавить виртуальный SetNumber к заявке

public class State 
{ 
    public int Number { get; set; } 

    public virtual void SetNumber(int n) 
    { 
     Number = n; 
    } 

    public void Execute(IAction action) 
    { 
     if (action.IsValid(this)) 
      action.Apply(this); 
    }    
} 

В выдвинутом состоянии вы orverride это

public class ExtendedState : State { 
    public int Number2 { get; set; } 

    public orverride void SetNumber(int n) 
    { 
     base.SetNumber(n); 
     Number2 = n; 
    } 
} 

Действие затем будет осуществляться как этот

public void Apply(State state)   
{ 
    state.SetNumber(5);   
}  

EDIT:

Что об объявлении номер как массив?

public class State 
{ 
    public int[] Numbers { get; private set; } 

    public State() 
    { 
     Numbers = new int[1]; 
    } 

    ... 
} 

Действие затем делает это

public void Apply(State state)   
{ 
    for (int i = 0; i < state.Numbers.Length; i++) { 
     state.Numbers[i] = 5; 
    } 
} 

Конструктор ExtendedState будет инициализировать Numbers с

Numbers = new int[2]; 

Кроме того, вы могли бы иметь свойства для отдельных номеров

public int Number { 
    get { return Numbers[0]; } 
    set { Numbers[0] = value; } 
} 

и

public int Number2 { 
    get { return Numbers[1]; } 
    set { Numbers[1] = value; } 
} 
+0

Хэнкс Оливье для ответа. Проблема в том, что у меня есть ~ бесконечное количество действий, поэтому * командный шаблон *. Ваше решение не подходит в моем случае ... Могу ли я что-то сделать для виртуализации команды Execute? –

Смежные вопросы