2014-02-07 77 views
1

這主要是一個重構問題。使用LinkedList重構類似的方法

我創造了一些方法,通過一個動作的履歷根據其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()方法幾乎完全相同。

我希望看看是否有一種很好的方式將此重構爲更通用的方法集而不是重複代碼? (注意 - 我的代碼不包含數據庫調用來減少閱讀,所以我將dummy數據放入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

解除複製某些邏輯的一種方法是使用訪問者模式。

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方法可能會更好。

+0

它確實看起來過度殺傷力,但我真的很想找到一個更通用的方法來解決您提供的問題。感謝您的解決方案並花時間回覆。 – JBond