代码改变世界

[设计模式]Memento pattern(备忘录模式)在Paint.net中的应用

2007-11-16 22:26  水随风  阅读(550)  评论(0编辑  收藏  举报


========Paint.Net====waterlion=======Memento pattern(备忘录模式)====设计模式======


Paint.net是一个开源的图像编辑软件,是由美国一所大学的学生所开发。在里面我们可以学到很多的知识,比如画图啊!设计模式啊!等等。看到paint.net同时也看到了.net的强大,那么多功能paint.net总共也只有几M而已,所有的操作都被封装。自己也按耐不住相试试模仿一下里面的功能。

当我想做一个Undo(撤销)的时候,我从中体验到了设计模式的应用在处理问题上的优点,Undo操作是将原先对画板的操作取消。那么我们来看看paint.net是如何体现这种模式的

首先说明Undo的一个过程,因为有很多画笔,很多效果,那么把这些效果或者是图片的形成条件放在一个类中,这些类的结构为:

 

HistoryMemento这个抽象类派生了很多的子类,这些子类就是根据不同的画笔或者效果而产生,目的就在于记录下产生这些画笔和效果的必要条件。

此下为HistoryMemento的部分代码

  public abstract class HistoryMemento
    {
        
private string name;
        
public string Name
        {
            
get
            {
                
return this.name;
            }

            
set
            {
                
this.name = value;
            }
        }

        
private ImageResource image;
        
public ImageResource Image
        {
            
get
            {
                
return this.image;
            }

            
set
            {
                
this.image = value;
            }
        }

        
protected int id;
        
private static int nextId = 0;
        
public int ID
        {
            
get
            {
                
return this.id;
            }

            
set
            {
                
this.id = value;
            }
        }
//.
  public HistoryMemento(string name, ImageResource image)
        {
            
this.name = name;
            
this.image = image;
            
this.id = Interlocked.Increment(ref nextId);
        }

又可见ToolHistoryMemento的记录类,该类继承于HistoryMemento

 public abstract class ToolHistoryMemento
        : HistoryMemento
    {
        
private DocumentWorkspace documentWorkspace;
        
private Type toolType;

        
protected DocumentWorkspace DocumentWorkspace
        {
            
get
            {
                
return this.documentWorkspace;
            }
        }

        
public Type ToolType
        {
            
get
            {
                
return this.toolType;
            }
        }

        
protected abstract HistoryMemento OnToolUndo();

        
protected sealed override HistoryMemento OnUndo()
        {
            
if (this.documentWorkspace.GetToolType() != this.toolType)
            {
                
this.documentWorkspace.SetToolFromType(this.toolType);
            }

            
return OnToolUndo();
        }

        
public ToolHistoryMemento(DocumentWorkspace documentWorkspace, string name, ImageResource image)
            : 
base(name, image)
        {
            
this.documentWorkspace = documentWorkspace;
            
this.toolType = documentWorkspace.GetToolType();
        }
    }


监视备忘类,此类为保存状态及封装数据结构所用

 public class HistoryStack
    {
        
private List<HistoryMemento> undoStack;
        
private List<HistoryMemento> redoStack;
        
        //被省略代码

        
private HistoryStack(
            List
<HistoryMemento> undoStack,
            List
<HistoryMemento> redoStack)
        {
            
this.undoStack = new List<HistoryMemento>(undoStack);
            
this.redoStack = new List<HistoryMemento>(redoStack);
        }

       
//被省略代码
        }
    }


回到正题,为什么我们要抽象此类并为之改善条件,我们的目的在哪?我们为了什么?我们为了让在画板上处理图片的操作过程中更好的完成Memento Pattern(备忘者模式)所带来的快乐,因为我的操作被上述不同的类保存下来了。

好的,我们保存了这些类,也就是说我们应该已经完成了对画笔或者效果的记录。因为我们在画图的时候,如果需要改动某一项,我们会根据这些项进行重绘(这个我还没在paint.net看到相应的代码),重绘后的效果就是Undo后的效果

 

那么在Undo的时候,我们不能随意的去做这些操作,因为我们要按一定的顺序来做。Paint.net的方法就是虚拟一个HistoryStack(操作历史栈),因为我们的许多操作都被这样定义 

 private List<HistoryMemento> undoStack;

 

从这里可以看出对于我们的操作都保存在List的集合中,这样原子化的好处就是每一个操作都是透明的。栈的结构就不在这赘述了。我们可以简化一下图来看

Memento Pattern(备忘者模式)是如何工作的:

 

 

当然在HistoryStack不只是有Undo还有Redo原理一样都是用Stack来存储顺序,用List来存储操作集合。


==========================================================

第一次写关于设计模式的文章。如有错误,还请大家毫无保留的提出!!!