私は次のインターフェースを持っています
interface IConsoleHistory
{
void Add(string entry);
HistoryEntry GetNextEntry();
HistoryEntry GetPreviousEntry();
void ResetHistoryMarker();
void Delete(HistoryEntry entry);
void DeleteEntireHistory();
}
public class HistoryEntry
{
public HistoryEntry(string value, int index, bool isCommand)
{
Value = value;
Index = index;
IsCommand = isCommand;
}
public string Value { get; private set; }
public int Index { get; private set; }
public bool IsCommand { get; private set; }
}
これに基づいて、InMemoryHistoryを実装しました。
public class InMemoryHistory : IConsoleHistory
{
protected List<string> History { get; private set; }
private int _currentIndex;
public InMemoryHistory() :this(new List<string>())
{
}
protected InMemoryHistory(List<string> history)
{
History = history;
_currentIndex = -1;
}
public virtual void Add(string entry)
{
History.Insert(0, entry);
}
public HistoryEntry GetNextEntry()
{
if (GetHighestIndex() > _currentIndex)
{
_currentIndex++;
return ReturnAtIndex(_currentIndex);
}
return null;
}
private int GetHighestIndex()
{
return History.Count - 1;
}
private int GetLowestIndex()
{
return History.Count > 0 ? 0 : -1;
}
public HistoryEntry GetPreviousEntry()
{
if (_currentIndex > GetLowestIndex())
{
_currentIndex--;
return ReturnAtIndex(_currentIndex);
}
_currentIndex = -1;
return null;
}
private HistoryEntry ReturnAtIndex(int index)
{
return new HistoryEntry(History[index], index, false);
}
public void ResetHistoryMarker()
{
_currentIndex = -1;
}
public void Delete(HistoryEntry entry)
{
if (History.ElementAtOrDefault(entry.Index) != null)
{
History.RemoveAt(entry.Index);
}
}
public void DeleteEntireHistory()
{
History.Clear();
}
}
今、私はファイルベースの履歴が欲しかった。コードをDRYに保つために、InMemoryHistoryから継承し、追加するたびにリスト全体を保持したいと思いました。
public class FileBasedHistory : InMemoryHistory
{
private readonly string _fileName;
public FileBasedHistory():this("history.txt")
{
}
public FileBasedHistory(string fileName) :base(GetHistoryFromFile(fileName))
{
_fileName = fileName;
}
public override void Add(string entry)
{
base.Add(entry);
WriteToDisk();
}
private void WriteToDisk()
{
using(var textWriter = new StreamWriter(_fileName, false, Encoding.UTF8))
{
History.ForEach(textWriter.WriteLine);
}
}
private static List<string> GetHistoryFromFile(string fileName)
{
if (!File.Exists(fileName))
return new List<string>();
return File
.ReadAllLines(fileName)
.ToList();
}
}
それは魅力のように機能します。でも気になるのは、静的GetHistoryFromFile
メソッドが必要なことです。それほど大したことではありませんが、この状況により適したパターンが欠けているのではないかと思います。
アップデート
キースがすでに示唆したように。それはちょっと私を悩ませている継承アプローチでもあります。継承は常に問題である必要があります。
「FileBasedHistoryはInMemoryHistoryです」とは言えません。
ですから、これにはStrategyPatternを使用する必要があるのではないかと思います。または、ロジックの一部を実装するが拡張の余地を残すAbstractConsoleを作成することもできます。それをリファクタリングする方法について何か提案はありますか?