我错过了什么样的模式

时间:2012-07-23 22:36:01

标签: c# .net oop design-patterns

我有以下界面

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来实现部分逻辑,但为扩展留出空间。关于如何重构它的任何建议?

3 个答案:

答案 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();

我认为这是一个不同的责任,我把它们移到了不同​​的班级。