北川广海の梦

北川广海の梦

设计模式:备忘录模式与组合模式

2021-11-10

备忘录模式

当我正在写下这篇博客的时候,我会不断的修修改改。Ctrl+Z组合键是我的好帮手。但是此时我编辑的内容是如何实现撤销的呢?答案就是通过备忘录模式。

假设当前编辑器的文本内容就是它的状态。我们可以通过一个栈来记录每次编辑的状态。但是现在我们只保存了文本,如果我们需要恢复光标的位置,或者更多的属性的时候,我们就不得不将它们全部暴漏出来。

通过备忘录模式,我们可以将生成快照的工作,委托给编辑器本身,编辑器自己是拥有对自己对象的完全访问权的。编辑器要做的,仅仅是根据自身的属性生成一个描述状态的对象。

public class EditorOriginator
    {
        public string Content { get; set; }

        public class Memento
        {
            private string Content { get; set; }

            public Memento(string content)
            {
                Content = content;
            }

            public string GetContent()
            {
                return this.Content;
            }
        }

        public Memento Save()
        {
            return new Memento(Content);
        }

        public void Restore(Memento memento)
        {
            Content = memento.GetContent();
        }
    }

    public class EditCaretaker
    {
        private readonly EditorOriginator _originator;

        private Stack<EditorOriginator.Memento> MementoHistory { get; }

        public EditCaretaker()
        {
            _originator = new EditorOriginator();
            MementoHistory = new Stack<EditorOriginator.Memento>();
        }

        public void Edit(string content)
        {
            _originator.Content = content;
            var memento = _originator.Save();
            MementoHistory.Push(memento);
        }

        public void Undo()
        {
            if (MementoHistory.TryPop(out var memento))
            {
                _originator.Restore(memento);
            }
        }
    }

组合模式

我们现在拥有一支军队,军队下面存在多个次级组织。我们现在作为军队的首领,如何让每一个单位都完成一件事情呢?例如,我现在需要知道军队的总人数。

通过组合模式,可以轻松的实现:

 public interface IComponent
    {
        public int GetNumber();
    }

    public abstract class Composite : IComponent
    {
        public List<IComponent> Children { get; set; }

        protected Composite(List<IComponent> children)
        {
            Children = children;
        }

        public int GetNumber()
        {
            return Children.Sum(t => t.GetNumber());
        }
    }

    public abstract class Leaf : IComponent
    {
        public int GetNumber()
        {
            return 1;
        }
    }

    public class ArmyLeader : Composite
    {
        public ArmyLeader(List<IComponent> children) : base(children)
        {
        }
    }

    public class Company : Composite
    {
        public Company(List<IComponent> children) : base(children)
        {
        }
    }

    public class Soldier : Leaf
    {
        
    }

军队首领下有多只连队,连队下有多个士兵。我们可以通过递归的方式,轻松的统计所有的人数。

在创建组合树的时候,我们可以使用构造器模式。
访问组合树,可以通过迭代器模式。