有没有办法避免方法调用重复?

时间:2015-02-10 00:52:41

标签: c# .net

我正在构建一个游戏,其中有几个方法链接到其他方法,需要在幕后调用。例如,当一名士兵需要离开城堡时,需要打开大门,然后在他离开后立即关闭:

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 个答案:

答案 0 :(得分:2)

你可以做到

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

OpenGate的位置

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

答案 1 :(得分:2)

这可能完全矫枉过正,但您可以随时实施IDisposable,然后使用using块。这是“确保”它发生的好方法。

如果你设置了一个在dispose上调用某个给定动作的类,

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

这种方法的一个很好的优点是它不会弄乱你的callstack,尽管它确实有一些开销。但是如果你把DelegateDisposable带到某个实用程序类中,它也可能对其他东西有用。

答案 2 :(得分:1)

我会对继承模式保持公正,这种模式会强制您在基础的继承抽象类的上下文中执行操作。我认为这是首选的原因是因为它允许您轻松封装Gate打开和关闭,并且不会暴露发生这种情况的条件或继承方案之外的功能。

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!