Реализация шаблона команды и полиморфизм - PullRequest
1 голос
/ 09 февраля 2012

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

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 (в противном случае вызываются не реализованные функции).

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

Ответы [ 3 ]

1 голос
/ 09 февраля 2012

Вы можете добавить виртуальный метод 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); 
    }             
} 

В расширенном состоянии вы переопределяете его

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

РЕДАКТИРОВАТЬ :

А как насчет объявления числа в виде массива?

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 голосов
/ 09 февраля 2012

Как насчет добавления StateContainer в State и Action:

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; }
}
0 голосов
/ 09 февраля 2012

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

interface IAction<TState> where TState: State
{
    bool IsValid(TState state);
    void Apply(TState state);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...