2015-02-10 3 views
2

Я создаю игру, в которой несколько методов привязаны к другим и нужно вызвать за кулисами. Например, когда солдат должен покинуть замок, ворота должны быть открыты, а затем закрываются, как только он покидает:Есть ли способ избежать повторения вызова метода?

public void MoveTheGate(bool openTheGate) 
{ 
    if (openTheGate) 
    { 
     // code for: open the gate 
    } 
    else 
    { 
     // code for: close the gate 
    } 
} 

public void GetOutOfTheCastle() 
{ 
    MoveTheGate(true); 

    // code for: get out of the castle 

    MoveTheGate(false); 
} 

То же самое верно, когда посланник из другого царства достигает замок, MoveTheGate() Метод должен быть назван как в начале, так и в конце входа посланника в замок.

Есть ли более деликатный способ достичь этого?

+3

Рабочий код вне темы для StackOverflow. Вы можете взглянуть на [Code Review] (http://codereview.stackexchange.com/). –

+0

Все зависит от того, что прокомментировал код.Если есть способ многократно использовать его, то определенно держите единственный метод. Опубликуйте полный код обзора кода, как предлагал @ Pierre-LucPineault. – krillgar

+1

Остерегайтесь, однако, Code Review не разрешает код-заглушку. Вам нужно будет опубликовать весь метод (ы). – Hosch250

ответ

2

вы могли бы сделать

OpenGate(()=> 
    { stuff to do with gate open } 
); 

где OpenGate является

public void OpenGate(Action action) 
{ 
    try 
    { 
     MoveTheGate(true); 
     action(); 
    } 
    finally 
    { 
    MoveTheGate(false); 
    } 
} 
2

Это может быть полным излишеством, но вы всегда можете реализовать IDisposable затем использовать using блок. Это хороший способ «убедиться», что это происходит.

Если вы создали класс, названный некоторое заданное действие на отчуждать,

public class DelegateDisposable : IDisposable 
{ 
    private readonly Action action; 

    public DelegateDisposable(Action action) 
    { 
     this.action = action; 
    } 

    public void Dispose() 
    { 
     if(this.action != null) 
     { 
      this.action(); 
     } 
    } 
} 

Тогда вы могли бы использовать его как это:

private IDisposable OpenGate() 
{ 
    MoveTheGate(true); 
    return new DelegateDisposable(() => MoveTheGate(false)); 
} 

и использовать его как это:

public void GetOutOfTheCastle() 
{ 
    using (OpenGate()) 
    { 
     // code for: get out of the castle 
    } 
} 

Приятным преимуществом этого подхода является то, что он не путается с вашим стоп-сигналом, хотя опять-таки, он имеет некоторые оверха Свинец. Но если вы принесли DelegateDisposable в какой-то класс утилиты, он, вероятно, может быть полезен и для чего-то другого.

+2

Хотя это действительно работает, он чувствует себя грязным, чтобы реализовать IDisposable, когда нет необходимой очистки неуправляемых ресурсов. –

+0

@DavidL Это компромисс между тем, что вы делаете в стеке вызовов, насколько чистым является код и ваши принципы. Я видел - хотя я не могу придумать, где - несколько проектов, которые я уважал, используя «IDisposable» для таких вещей, и я не против этого. Я как бы рассматриваю «ворота» как ресурс, который нуждается в очистке, хотя я определенно вижу вашу точку зрения - это не то же самое, что открытый поток или что-то еще. –

1

Я был бы беспристрастным шаблону наследования, который заставляет вас выполнять действия в контексте базового унаследованного абстрактного класса. Причина, по которой я считаю это предпочтительнее, заключается в том, что она позволяет вам легко инкапсулировать открытие и закрытие ворот и не выставлять ни условия для этого, ни эту функциональность за пределами унаследованного сценария.

public void Main() 
{ 
    var x = new InheritedAction(); 
} 

public abstract class BaseGateAction 
{ 
    public void PerformBaseAction(Action actionToPerformWhileGateIsOpen) 
    { 
     Open(); 
     actionToPerformWhileGateIsOpen(); 
     Close(); 
    } 

    private void Open() 
    { 
     Console.WriteLine("Gate has been opened"); 
    } 

    private void Close() 
    { 
     Console.WriteLine("Gate has been closed"); 
    } 
} 

public class InheritedAction : BaseGateAction 
{ 
    public InheritedAction() 
    { 
     PerformBaseAction(() => 
      Console.WriteLine("Attack the dragon while the gate is open")); 

     PerformBaseAction(() => 
     { 
      Console.WriteLine("Attack the dragon while the gate is open"); 
      Console.WriteLine("The dragon is victorious and you have been devoured"); 
     }); 
    } 
} 

Этот пример кода выводит следующий за оба метода PerformBaseAction называет соответственно:

Gate has been opened 
Attack the dragon while the gate is open 
Gate has been closed 

Gate has been opened 
Attack the dragon while the gate is open 
The dragon is victorious and you have been devoured 
Gate has been closed 

Это позволит не только лучше повторного использования кода, но гораздо более герметизированная логика. Вы всегда можете добавлять дополнительные открытые методы, которые принимают предварительные условия или пост-условия, которые повлияют на то, сможете ли вы открыть ворота.

public abstract class BaseGateAction 
{ 
    ....  
    public void PerformBaseActionWithPrecondition(Func<bool> precondition, Action actionToPerformWhileGateIsOpen) 
    { 
     if (precondition()) 
     { 
      PerformBaseAction(actionToPerformWhileGateIsOpen); 
     } 
     else 
     { 
      Console.WriteLine("The gate could not be opened!"); 
     } 
    } 
    ... 
} 

Это можно назвать следующим образом:

PerformBaseActionWithPrecondition<bool>(
     () => true == false, 
     () => Console.WriteLine("Attack!") 
    ); 

И выведет:

The gate could not be opened! 
Смежные вопросы