使用链接列表重构类似的方法

时间:2014-02-07 14:07:48

标签: c# refactoring

这主要是一个重构问题。

我正在创建一些方法来根据其Id / PreviousId关系返回/转发动作历史记录(请参阅下面的基本类):

public class Action
{
    public int Id { get; set; }
    public int PreviousId { get; set; }
    public string Title { get; set; }
}

背景信息:

我从数据库中获取单个操作开始。如果用户选择“GoBack”,我需要从数据库中获取先前的操作并将其存储在LinkedList中。这意味着用户可以重新访问相同的操作(即返回然后再返回),但是通过从LinkedList版本调用它而不是再次从数据库中获取它。我不想最初从数据库中检索所有操作。我有这个功能,但我的GoBack()和GoForward()方法完全相同。

我希望看到是否有一种很好的方法可以将其重构为更通用的方法集而不是重复代码? (注意 - 我的代码不包括减少读取的数据库调用,所以我把虚拟数据放入List中作为我的数据库。)

我在方法中引用的类级别变量:

   //The list I'm using to pretend to be my database containing actions
   private List<Action> _actions { get; set; }

   private Action _currentAction { get; set; } 
   private LinkedList<Action> _actionLinks { get; set; }

这是我的GoBack()方法:

   private void GoBack()
   {
       var current = _actionLinks.Find(_currentAction);

       if (current == null)
           return;

       //If we've already stored the previous action. Just point to it
       if (current.Previous != null)
       {
           _currentAction = current.Previous.Value;
           return;
       }

       //We don't have this action stored so go get it from the database and cache it in the list
       var previousAction = _actions.FirstOrDefault(i => i.Id == _currentAction.PreviousId);

       //There are no previous actions
       if(previousAction == null)
           return;

       _actionLinks.AddBefore(current, previousAction);

       //Now reset the current action
       _currentAction = previousAction;
   }

这是我的GoForward()方法:

   private void GoForward()
   {
       var current = _actionLinks.Find(_currentAction);

       if (current == null)
           return;

       //If we've already stored the next action. Just point to it
       if (current.Next != null)
       {
           _currentAction = current.Next.Value;
           return;
       }

       //We don't have this action stored so go get it from the database and cache it in the list
       var nextAction = _actions.FirstOrDefault(i => i.PreviousId == _currentAction.Id);

       //There are no further actions
       if (nextAction == null)
           return;

       _actionLinks.AddAfter(current, nextAction);

       //Now reset the current action
       _currentAction = nextAction;
   }

如果要编译代码。我已经在我的构造函数和BuildData方法中添加了我用来测试它:

构造

   public LinkListTest()
   {
       _actionLinks = new LinkedList<Action>();
       _actions = new List<Action>();
       BuildData();

       //Just set current to the latest action id
       _currentAction = _actions.First(i => i.Id == 6);

       //Add it to the linkedlist
       _actionLinks.AddFirst(_currentAction);

       //Start navigating as a user would
       GoBack();
       GoBack();
       GoForward();
       GoBack();
       GoForward();
       GoBack();
       GoBack();
   }

BuildData方法:

   private void BuildData()
   {
       for (int i = 6; i >= 0; i--)
       {
           var action = new Action();
           action.Id = i;
           if (i != 0)
               action.PreviousId = i - 1;
           else
               action.PreviousId = -1;

           action.Title = string.Format("Action {0}", i);

           _actions.Add(action);
       }
   }

提前致谢!

1 个答案:

答案 0 :(得分:1)

这里去除一些逻辑的一种方法是使用访问者模式。

    using ActionListAction = System.Action<System.Collections.Generic.LinkedList<Package.Action>, System.Collections.Generic.LinkedListNode<Package.Action> ,Package.Action>;

    ...

    private void GoBack()
    {
        Move(new BackwordVisitor());
    }

    private void GoForward()
    {
        Move(new ForwardVisitor());
    }

    private void Move(DirectionVisitor direction)
    {
        var current = _actionLinks.Find(_currentAction);

        if (current == null)
            return;

        var node = direction.Pointer(current);
        if (node != null)
        {
            _currentAction = node.Value;
            return;
        }

        var action = _actions.FirstOrDefault(i => direction.NextSelector(i, _currentAction));

        //There are no further actions
        if (action == null)
            return;

        direction.Add(_actionLinks, current, action);

        _currentAction = action;           
    }

    private abstract class DirectionVisitor
    {
        public Func<LinkedListNode<Action>, LinkedListNode<Action>> Pointer { protected set; get; }
        public Func<Action, Action, bool> NextSelector { protected set; get; }
        public ActionListAction Add { protected set; get; }  
    }

    private class ForwardVisitor : DirectionVisitor
    {
        public Forward()
        {
            Pointer = n => n.Next;
            NextSelector = (action, current) => action.PreviousId == current.Id;
            Add = (list, current, node) => list.AddAfter(current, node);
        }   
    }

    private class BackwordVisitor : DirectionVisitor
    {
        public Backword()
        {
            Pointer = n => n.Previous;
            NextSelector = (action, current) => action.Id == current.PreviousId;
            Add = (list, current, node) => list.AddBefore(current, node);
        }            
    }

由于只有两个选项可以在列表中移动,因此对于此特定方案而言可能过度。使用方向和使用条件将枚举传递到Move方法可能会更好。