我有以下界面
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,并在每次添加后保留整个List。
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
方法。这不是什么大问题,但我想知道我是否错过了一种更适合这种情况的模式?
更新
正如基思已经建议的那样。它也是一种困扰我的继承方法。继承应始终是是的问题。
你不能说:&#34; FileBasedHistory 是 InMemoryHistory&#34;
所以我想知道我是否应该尝试使用 StrategyPattern 。或者编写一个AbstractConsole来实现部分逻辑,但为扩展留出空间。关于如何重构它的任何建议?
答案 0 :(得分:2)
我发现你作为构造函数传递列表很奇怪。你根本不必这样做......
不是将GetHistoryFromFile视为创建新列表,而是将其视为加载到现有列表中的方法(它也变得更加普遍有用......因为它可以将多个文件加载到历史记录中)。
同时删除和清除不能正常写入磁盘...
同时逐行写入磁盘可能会变得很慢......
此外,您的InMemory和基于文件的存储可能会遇到巧合的耦合。在他们目前相似的意义上,他们可能有分歧的机会。例如,如果基于磁盘的系统使用滚动历史记录文件和缓存历史记录。因此,不要过于依赖InMemory和File来保留继承结构,将它们分开可能更容易
答案 1 :(得分:1)
我认为你已经完美了。 GetHistoryFromFile
仅适用于FileBasedHistory
,因此它应该存在。
答案 2 :(得分:0)
您可以在此处使用Iterator
。这三种方法仅用于迭代数据:
HistoryEntry GetNextEntry();
HistoryEntry GetPreviousEntry();
void ResetHistoryMarker();
这些方法用于管理数据:
void Add(string entry);
void Delete(HistoryEntry entry);
void DeleteEntireHistory();
我认为这是一个不同的责任,我把它们移到了不同的班级。