阿扁向各位大侠请教有关 Undo-Redo 功能的实现方法。

时间:2023-01-25 16:51:25
阿扁正在做一个 WYSWYG 的设计器,基本上是模仿了 VS.NET 的界面设计器风格。

基本部分我都已基本实现了,可像 VS.NET 一样强大的 Undo-Redo 功能,我还正摸不着头脑。

用户的每次操作都可能引起某些数据的更改,如何“高效”地记忆数据更改历史和相应的状态,我苦思冥想也想不出一个好的方法来解决。

恳请各位大侠不吝赐教。

48 个解决方案

#1


set it to top .

whether use cache can achieve it ?

#2


gz

#3


这类似一个编辑器的模式
我会这样的
让每个有数据载体的对象拥有个数据链,可以是不限长度,也可以限长度
就可以回退的
:)仅供参考

#4


SendKeys.Send("^Z");不可以吗?

#5


首先定义一个抽像基类 Command.它包括两个抽像方法.用作所有操作的基类.

 public abstract class Command
 {
    public abstract void Undo();
    public abstract void Redo();
 }
一个管理Command集合的类 CommandCollection.
public class CommandCollection : CollectionBase
  {

    public Command this[int index]
    {
      get
      {
        return List[index] as Command;
      }

      set
      {
        List[index] = value;
      }
    }

    public Command Add(Command value)
    {
      List.Add(value);
      return value;
    }

    public void Add(Command[] values)
    {
      Command[] commands = values;
      for (int i = 0; i < (int)commands.Length; i++)
      {
        Command command = commands[i];
        Add(command);
      }
    }

    public void Remove(Command value)
    {
      List.Remove(value);
    }

    public void RemoveRange(int index, int count)
    {
      for (int i = index; i < index + count; i++)
      {
        List.RemoveAt(index);
      }
    }

    public void Insert(int index, Command value)
    {
      List.Insert(index, value);
    }

    public bool Contains(Command value)
    {
      return List.Contains(value);
    }

    public int IndexOf(Command value)
    {
      return List.IndexOf(value);
    }
}
一个实现类似堆栈机制的类.用CommandCollection来保存所有做过的操作(用Command来表示).并实现Redo,Undo操作.

 class CommandStack
  {
    private CommandCollection commands = new CommandCollection();

    private int position = -1;

    private int modifiedPosition = -1;


    public int Position
    {
      get
      {
        return position;
      }
    }

    public void Add(Command command)
    {
      if (CanRedo())
      {
        commands.RemoveRange(position + 1, commands.Count - position - 1);
      }
      commands.Add(command);
      position = commands.Count - 1;
    }

    public void Undo()
    {
      if (!CanUndo())
      {
        throw new ....
      }
      commands[position--].Undo();
    }

    public void Redo()
    {
      if (!CanRedo())
      {
        throw new ...
      }
      commands[position++].Redo();
    }

    public bool CanUndo()
    {
      return (position == -1) == false;
    }

    public bool CanRedo()
    {
      return (position == commands.Count - 1) == false;
    }

    public bool IsModified()
    {
      return (modifiedPosition == position) == false;
    }

    public void Save()
    {
      modifiedPosition = position;
    }

    public void Clear()
    {
      commands.Clear();
      position = -1;
      modifiedPosition = -1;
    }
  }
然后为所有能可能的操作从分别从Command中派生一个类,就是说每个操作用一个类来表示.比如增加一个字符:

class AddCommand : Command
  {
    private char target

    private IList list;

    private int position;


    public AddCommand(char target, IList list, int position)
    {
      this.target = target;
      this.list = list;
      this.position = position;
    }

    public override void Undo()
    {
      list.RemoveAt(position);
    }

    public override void Redo()
    {
      list.Insert(position, target);
    }
  }

这个只是一个示例....

至此,问题已经很明朗了..问题的关键就在于把Command的子类一定要设计好,并且每一步Redo,Undo都是原子,就是不能再分割的操作..Command的子类设计好了.问题基本也就解决了.

只是这么疑难的问题..100分是不是少了点 :)

#6



TO: haiwangstar(南河三(来自于小犬星座))  
   分数不是问题,如果能帮我完全解决掉问题,Money 也是可以商量的。
   你的代码和思路很有价值。

结帖时,肯定会加分。

#7


TO AhBian(阿扁) :

客气了,开个玩笑.对你解决问题有所帮助就是最好.

#8


用sendMessage的API啊,一查就知道的嘛
如:sendMessage(控件句柄,EM_UNDO,0,0);这样就行了,如果是redo一样的啊
常量和API都要声明,呵呵

#9


TO zoujiaming(笨笨的!) :
真是高手。:-)

#10


现在到是有点思路了,但我的看法是采用接口来做,而不是抽象类。这样我想更好。
另外重要的是设计器界面状态的 Undo-Redo,主要就是指每次状态变化哪些对象正被选中,
也必须处理好。

希望听到更多意见。

#11


haiwangstar的是正解,这是command模式的典型应用

#12


没做过,友情贴个连接 ,也就是GOOGLE搜索出来的第一个了:D
http://www.javaworld.com/javaworld/jw-06-1998/jw-06-undoredo.html

#13


看来搜索水平也是有高低的,我就没搜索到这个链接,学习。

#14


对啊,搜索技巧现在也很重要,哪些朋友有些心得希望也能分享出来。

#15


Google实用搜索技巧

http://news.onlinedown.net/info/12864.htm

#16


参考一下SharpDevelop的实现,看看他的源代码。

#17


分数不是问题,如果能帮我完全解决掉问题,Money 也是可以商量的。
   你的代码和思路很有价值。
??????????!!!!!!!!!!!!!!!!!!!!

我想说:靠!!!!

我不知道你是怎么到一颗红星的!!!
我很奇怪!!!
也非常纳闷!!!
你作为一个程序员!!!
竟然连设计模式都没有看过!!!没有看过??!!!!
这分明是设计模式里最经典的command模式所能解决的问题!!
你看过设计模式吗??!!!
如果没有看过!!身为程序员你不觉得羞耻吗??!!!!
难道以后还要碰到一丁点的小问题就要拿钱来求人解决吗???

#18


难道你不知道如果没看过设计模式你在这里会问多少道问题吗?

#19


TO: chestnuts(c# Sharp) 
指教的是,感谢你能这么严肃的批评我。

这里的高手的确很多,也真是我来这里提问的原因。
我相信 chestnuts 也算一位,的确高手不是用几颗星来衡量的。

为了表示对你的敬佩,现将我拿到一星的原因向你汇报:
我得一星的主要原因是专家分超过了 5000 分,这些专家分都是来自其他 CSDN 账号。可能某些分是某些朋友有眼无珠,乱给的,所以要打掉水分,打个六折的话,可能现在还能剩 5000 分,看来一星要降也挺难。

关于设计模式的知识我的确学得不多,虽然看过 COMMAND 模式,但没想到能用在这方面,我的确很菜,是吗?以后要在这方面好好用功一点了。

关于钱的问题,主要是从 Bill Gates 老兄那儿学来的。
都是他出的瘦主意,他倒好,已经是个天才了,还出钱聘了那么多的高手程序员替他写程序,后来居然发达了,成了软件皇帝,还成了世界首富。
瞅着他这么发达,我眼红得很,一时糊涂,钱迷心窍,想想 BILL 这么个天才还用钱请人做,我这个菜鸟没有理由不这么做,所以就用了这么一个招你批评的烂招。
可又想想,这个世界上象这样钱迷心窍的人实在太多了,我真为他们和自己感到“羞耻”。

还有,你可能来这个论坛时间并不长,我的历史要近二年了,主要因为自己时间不够,否则可能要上三、四星了。看来真的高手不是用星的多少来衡量的,象你 5 三角也已是高手,不能因为你没上星,就说你不是高手。

有个建议:上星的朋友应该好好自查一下——自己配不配那么多星?
自查时建议以 chestnuts(c# Sharp) 作为参照。
如果自认为不配的话,可以向总版主申请降级。

#20


嘿嘿~,说的好,程序员又不是超人,程序员也有高低之分,哪能什么都懂。
现在一切讲究效率,用最快方法解决当前问题固然好。
有时间可以慢慢学习,但在一个比较急的项目中,谁敢跟老板说,这个问题问别人很容易解决,但是老板您老大给个十天半个月时间让我研究研究好不好?

#21


有个建议给版主们:
      在会员升星前,要加试是否掌握软件设计模式,尤其是 Command 模式,
      如果通不过,就不能升星。

有个建议给已升星的朋友们:
      如果有问题要问,请注册一个新的马甲账号,用此账号提问,这样可以......
      为什么要这么做?不用我说了吧

#22


有点意思

#23


该回复于2014-07-30 00:36:19被版主删除

#24


我来说两句.

阿扁很幽默,也很谦虚.

其实我觉的chestnuts(c# Sharp) 大可不必!

软件开发涉及的领域如此之广,没有一个人敢说自己在各个领域都很精通.Bill Gates最精通的BASIC(当然BILL最牛的应该是商业才能),Anders是搞语言设计,编译器设计... ...每个人都有自己的领域,专长.像他们这么牛的人,也都只是在自己的一个领域内做了成绩.何况我们普通普通的人呢. 即使一个编程高手,也不可能在所有的领域都那么精通吧. 我想起有一个朋友,原来是作项目经理的,现在同别人合作开了家公司.技术非常的棒,经验很丰富.几乎我每一次问他问题,(问题可能涉及各个领域)他都会给我让我非常满意的答案,也感到学到了不少东西.可有一次,我问他一个关于SOAP协议的东东.他居然说:SOAP是什么东东?.我说:是一个协议,简单对象访问协议,是基于XML的.他说:哦,那是XML的一种应用而已了.没必要搞个什么名词. 看来,他是没有涉足,研究过这个东西.难道就凭这一点,就能说人家不行,就全盘否定了吗?

我觉的每个人都有自己专长和不专长的地方,也没有一个"高手"是全能的.即使是"程序员必须掌握的,最经典的东西",又有几人敢拍着胸脯说:我一点问题都没有.我记得林锐说过这样的话:没几个人敢拍着胸脯说,我对C语言中的指针,手动内存管理一点问题都没有了,包括我自己.(大意是这样)这是作为一个计算机博士,上海贝尔的软件工程师说过的话.何等的谦虚...

尺有所短,寸有所长.

#25


呵呵,有意思,那我想学软件设计模式,大概要看什么书

#26


up

#27


我说我怎么这么菜,原来是不懂设计模式,不知道要怎么入门!
另外楼主叫什么昵称不好,叫个阿扁,有点儿找人骂得感觉啊

#28


学习中....

#29


怎么后来跑题了啊?
最后楼主有答案了吗?
小弟就想什么说什么了。

看了几个重要的发言,觉得haiwangstar(南河三(来自于小犬星座))的方案是比较常用的command模式。有几点也提一下。

第一、每个操作都要写undo\redo,但很难把操作细化到合适的程度。比如:我一开始有两个操作一个是画圆,一个是画方,有两个class,继承接口,实现undo\redo方法。但后来我发现我还需要一个操作把画方,画圆联合起来,并undo要同时进行,就是类似事务。这样,必须再创建一个class,来做画方,画圆的操作。但实际上前面两个class已经有这样的操作,创建第三个是代码的重复,如此......
解决方案是创建类似事务的机制管理,当然没有真的事务那么复杂,简单的讲就可以是设置标志为表明多个操作是在一个事务内的。

第二、undo操作的时候,如果数据复杂,或是性能消耗很大,其实是不合算的,比如远程的数据库操作。还不如重新再作一边,更简洁。

小弟完全是个人意见,请大虾们不要见怪。

#30


就凭这么清析的条理反驳别人的恶意什么的,值个星星应该够了啊。
其实好的程序应该是简洁高效,最大的发挥他商业价值的程序吧
 有时参考别人的代码,反倒使自已思维受限

#31


谢谢 aboush(无人居)。

第一点其实是涉及到了原子操作问题,haiwangstar 也已有所提及。
第二点在我的应用中不必考虑,因为我做的就是与 VS.NET 类似的窗体或控件设计器差不多的东西,没有涉及到远程资源。

这个 Undo-Redo 功能我还没有开始做,正酝酿之中。
如果有了我认为好的解决方案,我也会在此帖中与大家一起讨论的。

Command 模式是很有效,但就解决 Undo-Redo 功能来说可能还是不够的。

#32


关注,我也在做

aboush(无人居)说得对,这里面有个如何划分,组合操作的问题

这个就要根据具体问题具体分析了

对于窗体或控件设计器中的undo/redo,SharpDevelp这个开源项目中有实现

不过他的代码看的太累

希望能有进展和大家分享

#33


等等~~!!!
阿扁懂写程序么???没有吧

#34


你知道阿扁怎么会最后胜出的吗?
因为选票统计软件就是阿扁写的。

#35


提个思路:
你的设计界面, 包括每个对象的属性,状态, 最终是否能用类似xml的东西来进行描述呢?
相信已经有比较好的纯文本的增量算法,现在的文本编辑器不都支持无限次undo/redo么。

#36


学习

#37


我也想知!

#38


#39


风吹两面,树在摇,但根不动。
不要因为一句吧话就放在心上,好多事,想开就好。何况,林子大了,什么鸟都有些。
另:
可以通过堆的原理去想一下这个问题,可能会有所帮助。

#40


学习关注中

#41


to  redbb 
你给的网页打不开

在此请大家有空看看这个贴,分享搜索心得
http://community.csdn.net/Expert/topic/3102/3102577.xml?temp=.6999933

#42


阿扁??

#43


to  hychieftain(不同) 我也打不开,我也是一个搜索的菜鸟。

to AhBian(阿扁) 
   阿扁从来都很幽默啊,呵呵

个人认为阿扁的水平是勿庸置疑的
倒是看了有位兄弟的置疑之后
决定我应该弄一个三角挂挂
不好意思,太菜了

#44


设计模式!

#45


看来这个帖子还没结,我也进来看看热闹,同时表示对 阿扁为人的 认可

#46


看来这个帖挂在上面也没什么意思了。
现在 CSDN 的人气(以及人气的质量)真的不能跟一年前比了。

尽管我还没开始动手写这部分的代码,但基本方略也是有了。
基本上还是参照有些朋友建议的 SharpDevelop 的源代码。

不过,这个源代码的确很难读,关键是这个源代码不能用 VS.NET 来读(要想迁移到 VS.NET也很难)。我花了不少力气,终于读懂了大半,也知道了哪些可以借用,哪些不适合的应该去除。

如果真的用 SharpDevelop 来开发真正的应用,我和项目都会趴下的(个人能力所致)。


重点感谢以下朋友:
 haiwangstar(南河三(来自于小犬星座)) 
 idiotzeng(白痴) 
 IMarksman(唉!为什么总是睡不醒呢?) 
 aboush(无人居)
 Jim3(Jim) 
 cocosoft(pengyun)
 brightheroes(闭关|特别想砍暗黑......) 


等我目前手上的活儿忙完了,我马上会做这部分。做好了,我会另开帖或者发表一篇专题与大家分享我的实现。

最后加分结帖,可惜我只能加到 200 分。

#47


另外特别致谢:
 chestnuts(c# Sharp)

尽管我个人认为你的观点是偏激的,且略带有一些挑战性。
但你对本帖态度是认真的,而我个人认为这一点也是很重要的。

大家都素昧谋面,但宽容与和气是必须的,尽管争论可以面红耳赤。

#48


这么看中那个星是什么意思

我到是想请教AhBian (阿扁) 兄几个问题

不能说请教 
是请指点
我也在做类似的一个东西
只是现在没有什么明确的思路不知道该如何下手
能否把你的代码给我SEESEE
tianyamoon010@163.com

#1


set it to top .

whether use cache can achieve it ?

#2


gz

#3


这类似一个编辑器的模式
我会这样的
让每个有数据载体的对象拥有个数据链,可以是不限长度,也可以限长度
就可以回退的
:)仅供参考

#4


SendKeys.Send("^Z");不可以吗?

#5


首先定义一个抽像基类 Command.它包括两个抽像方法.用作所有操作的基类.

 public abstract class Command
 {
    public abstract void Undo();
    public abstract void Redo();
 }
一个管理Command集合的类 CommandCollection.
public class CommandCollection : CollectionBase
  {

    public Command this[int index]
    {
      get
      {
        return List[index] as Command;
      }

      set
      {
        List[index] = value;
      }
    }

    public Command Add(Command value)
    {
      List.Add(value);
      return value;
    }

    public void Add(Command[] values)
    {
      Command[] commands = values;
      for (int i = 0; i < (int)commands.Length; i++)
      {
        Command command = commands[i];
        Add(command);
      }
    }

    public void Remove(Command value)
    {
      List.Remove(value);
    }

    public void RemoveRange(int index, int count)
    {
      for (int i = index; i < index + count; i++)
      {
        List.RemoveAt(index);
      }
    }

    public void Insert(int index, Command value)
    {
      List.Insert(index, value);
    }

    public bool Contains(Command value)
    {
      return List.Contains(value);
    }

    public int IndexOf(Command value)
    {
      return List.IndexOf(value);
    }
}
一个实现类似堆栈机制的类.用CommandCollection来保存所有做过的操作(用Command来表示).并实现Redo,Undo操作.

 class CommandStack
  {
    private CommandCollection commands = new CommandCollection();

    private int position = -1;

    private int modifiedPosition = -1;


    public int Position
    {
      get
      {
        return position;
      }
    }

    public void Add(Command command)
    {
      if (CanRedo())
      {
        commands.RemoveRange(position + 1, commands.Count - position - 1);
      }
      commands.Add(command);
      position = commands.Count - 1;
    }

    public void Undo()
    {
      if (!CanUndo())
      {
        throw new ....
      }
      commands[position--].Undo();
    }

    public void Redo()
    {
      if (!CanRedo())
      {
        throw new ...
      }
      commands[position++].Redo();
    }

    public bool CanUndo()
    {
      return (position == -1) == false;
    }

    public bool CanRedo()
    {
      return (position == commands.Count - 1) == false;
    }

    public bool IsModified()
    {
      return (modifiedPosition == position) == false;
    }

    public void Save()
    {
      modifiedPosition = position;
    }

    public void Clear()
    {
      commands.Clear();
      position = -1;
      modifiedPosition = -1;
    }
  }
然后为所有能可能的操作从分别从Command中派生一个类,就是说每个操作用一个类来表示.比如增加一个字符:

class AddCommand : Command
  {
    private char target

    private IList list;

    private int position;


    public AddCommand(char target, IList list, int position)
    {
      this.target = target;
      this.list = list;
      this.position = position;
    }

    public override void Undo()
    {
      list.RemoveAt(position);
    }

    public override void Redo()
    {
      list.Insert(position, target);
    }
  }

这个只是一个示例....

至此,问题已经很明朗了..问题的关键就在于把Command的子类一定要设计好,并且每一步Redo,Undo都是原子,就是不能再分割的操作..Command的子类设计好了.问题基本也就解决了.

只是这么疑难的问题..100分是不是少了点 :)

#6



TO: haiwangstar(南河三(来自于小犬星座))  
   分数不是问题,如果能帮我完全解决掉问题,Money 也是可以商量的。
   你的代码和思路很有价值。

结帖时,肯定会加分。

#7


TO AhBian(阿扁) :

客气了,开个玩笑.对你解决问题有所帮助就是最好.

#8


用sendMessage的API啊,一查就知道的嘛
如:sendMessage(控件句柄,EM_UNDO,0,0);这样就行了,如果是redo一样的啊
常量和API都要声明,呵呵

#9


TO zoujiaming(笨笨的!) :
真是高手。:-)

#10


现在到是有点思路了,但我的看法是采用接口来做,而不是抽象类。这样我想更好。
另外重要的是设计器界面状态的 Undo-Redo,主要就是指每次状态变化哪些对象正被选中,
也必须处理好。

希望听到更多意见。

#11


haiwangstar的是正解,这是command模式的典型应用

#12


没做过,友情贴个连接 ,也就是GOOGLE搜索出来的第一个了:D
http://www.javaworld.com/javaworld/jw-06-1998/jw-06-undoredo.html

#13


看来搜索水平也是有高低的,我就没搜索到这个链接,学习。

#14


对啊,搜索技巧现在也很重要,哪些朋友有些心得希望也能分享出来。

#15


Google实用搜索技巧

http://news.onlinedown.net/info/12864.htm

#16


参考一下SharpDevelop的实现,看看他的源代码。

#17


分数不是问题,如果能帮我完全解决掉问题,Money 也是可以商量的。
   你的代码和思路很有价值。
??????????!!!!!!!!!!!!!!!!!!!!

我想说:靠!!!!

我不知道你是怎么到一颗红星的!!!
我很奇怪!!!
也非常纳闷!!!
你作为一个程序员!!!
竟然连设计模式都没有看过!!!没有看过??!!!!
这分明是设计模式里最经典的command模式所能解决的问题!!
你看过设计模式吗??!!!
如果没有看过!!身为程序员你不觉得羞耻吗??!!!!
难道以后还要碰到一丁点的小问题就要拿钱来求人解决吗???

#18


难道你不知道如果没看过设计模式你在这里会问多少道问题吗?

#19


TO: chestnuts(c# Sharp) 
指教的是,感谢你能这么严肃的批评我。

这里的高手的确很多,也真是我来这里提问的原因。
我相信 chestnuts 也算一位,的确高手不是用几颗星来衡量的。

为了表示对你的敬佩,现将我拿到一星的原因向你汇报:
我得一星的主要原因是专家分超过了 5000 分,这些专家分都是来自其他 CSDN 账号。可能某些分是某些朋友有眼无珠,乱给的,所以要打掉水分,打个六折的话,可能现在还能剩 5000 分,看来一星要降也挺难。

关于设计模式的知识我的确学得不多,虽然看过 COMMAND 模式,但没想到能用在这方面,我的确很菜,是吗?以后要在这方面好好用功一点了。

关于钱的问题,主要是从 Bill Gates 老兄那儿学来的。
都是他出的瘦主意,他倒好,已经是个天才了,还出钱聘了那么多的高手程序员替他写程序,后来居然发达了,成了软件皇帝,还成了世界首富。
瞅着他这么发达,我眼红得很,一时糊涂,钱迷心窍,想想 BILL 这么个天才还用钱请人做,我这个菜鸟没有理由不这么做,所以就用了这么一个招你批评的烂招。
可又想想,这个世界上象这样钱迷心窍的人实在太多了,我真为他们和自己感到“羞耻”。

还有,你可能来这个论坛时间并不长,我的历史要近二年了,主要因为自己时间不够,否则可能要上三、四星了。看来真的高手不是用星的多少来衡量的,象你 5 三角也已是高手,不能因为你没上星,就说你不是高手。

有个建议:上星的朋友应该好好自查一下——自己配不配那么多星?
自查时建议以 chestnuts(c# Sharp) 作为参照。
如果自认为不配的话,可以向总版主申请降级。

#20


嘿嘿~,说的好,程序员又不是超人,程序员也有高低之分,哪能什么都懂。
现在一切讲究效率,用最快方法解决当前问题固然好。
有时间可以慢慢学习,但在一个比较急的项目中,谁敢跟老板说,这个问题问别人很容易解决,但是老板您老大给个十天半个月时间让我研究研究好不好?

#21


有个建议给版主们:
      在会员升星前,要加试是否掌握软件设计模式,尤其是 Command 模式,
      如果通不过,就不能升星。

有个建议给已升星的朋友们:
      如果有问题要问,请注册一个新的马甲账号,用此账号提问,这样可以......
      为什么要这么做?不用我说了吧

#22


有点意思

#23


该回复于2014-07-30 00:36:19被版主删除

#24


我来说两句.

阿扁很幽默,也很谦虚.

其实我觉的chestnuts(c# Sharp) 大可不必!

软件开发涉及的领域如此之广,没有一个人敢说自己在各个领域都很精通.Bill Gates最精通的BASIC(当然BILL最牛的应该是商业才能),Anders是搞语言设计,编译器设计... ...每个人都有自己的领域,专长.像他们这么牛的人,也都只是在自己的一个领域内做了成绩.何况我们普通普通的人呢. 即使一个编程高手,也不可能在所有的领域都那么精通吧. 我想起有一个朋友,原来是作项目经理的,现在同别人合作开了家公司.技术非常的棒,经验很丰富.几乎我每一次问他问题,(问题可能涉及各个领域)他都会给我让我非常满意的答案,也感到学到了不少东西.可有一次,我问他一个关于SOAP协议的东东.他居然说:SOAP是什么东东?.我说:是一个协议,简单对象访问协议,是基于XML的.他说:哦,那是XML的一种应用而已了.没必要搞个什么名词. 看来,他是没有涉足,研究过这个东西.难道就凭这一点,就能说人家不行,就全盘否定了吗?

我觉的每个人都有自己专长和不专长的地方,也没有一个"高手"是全能的.即使是"程序员必须掌握的,最经典的东西",又有几人敢拍着胸脯说:我一点问题都没有.我记得林锐说过这样的话:没几个人敢拍着胸脯说,我对C语言中的指针,手动内存管理一点问题都没有了,包括我自己.(大意是这样)这是作为一个计算机博士,上海贝尔的软件工程师说过的话.何等的谦虚...

尺有所短,寸有所长.

#25


呵呵,有意思,那我想学软件设计模式,大概要看什么书

#26


up

#27


我说我怎么这么菜,原来是不懂设计模式,不知道要怎么入门!
另外楼主叫什么昵称不好,叫个阿扁,有点儿找人骂得感觉啊

#28


学习中....

#29


怎么后来跑题了啊?
最后楼主有答案了吗?
小弟就想什么说什么了。

看了几个重要的发言,觉得haiwangstar(南河三(来自于小犬星座))的方案是比较常用的command模式。有几点也提一下。

第一、每个操作都要写undo\redo,但很难把操作细化到合适的程度。比如:我一开始有两个操作一个是画圆,一个是画方,有两个class,继承接口,实现undo\redo方法。但后来我发现我还需要一个操作把画方,画圆联合起来,并undo要同时进行,就是类似事务。这样,必须再创建一个class,来做画方,画圆的操作。但实际上前面两个class已经有这样的操作,创建第三个是代码的重复,如此......
解决方案是创建类似事务的机制管理,当然没有真的事务那么复杂,简单的讲就可以是设置标志为表明多个操作是在一个事务内的。

第二、undo操作的时候,如果数据复杂,或是性能消耗很大,其实是不合算的,比如远程的数据库操作。还不如重新再作一边,更简洁。

小弟完全是个人意见,请大虾们不要见怪。

#30


就凭这么清析的条理反驳别人的恶意什么的,值个星星应该够了啊。
其实好的程序应该是简洁高效,最大的发挥他商业价值的程序吧
 有时参考别人的代码,反倒使自已思维受限

#31


谢谢 aboush(无人居)。

第一点其实是涉及到了原子操作问题,haiwangstar 也已有所提及。
第二点在我的应用中不必考虑,因为我做的就是与 VS.NET 类似的窗体或控件设计器差不多的东西,没有涉及到远程资源。

这个 Undo-Redo 功能我还没有开始做,正酝酿之中。
如果有了我认为好的解决方案,我也会在此帖中与大家一起讨论的。

Command 模式是很有效,但就解决 Undo-Redo 功能来说可能还是不够的。

#32


关注,我也在做

aboush(无人居)说得对,这里面有个如何划分,组合操作的问题

这个就要根据具体问题具体分析了

对于窗体或控件设计器中的undo/redo,SharpDevelp这个开源项目中有实现

不过他的代码看的太累

希望能有进展和大家分享

#33


等等~~!!!
阿扁懂写程序么???没有吧

#34


你知道阿扁怎么会最后胜出的吗?
因为选票统计软件就是阿扁写的。

#35


提个思路:
你的设计界面, 包括每个对象的属性,状态, 最终是否能用类似xml的东西来进行描述呢?
相信已经有比较好的纯文本的增量算法,现在的文本编辑器不都支持无限次undo/redo么。

#36


学习

#37


我也想知!

#38


#39


风吹两面,树在摇,但根不动。
不要因为一句吧话就放在心上,好多事,想开就好。何况,林子大了,什么鸟都有些。
另:
可以通过堆的原理去想一下这个问题,可能会有所帮助。

#40


学习关注中

#41


to  redbb 
你给的网页打不开

在此请大家有空看看这个贴,分享搜索心得
http://community.csdn.net/Expert/topic/3102/3102577.xml?temp=.6999933

#42


阿扁??

#43


to  hychieftain(不同) 我也打不开,我也是一个搜索的菜鸟。

to AhBian(阿扁) 
   阿扁从来都很幽默啊,呵呵

个人认为阿扁的水平是勿庸置疑的
倒是看了有位兄弟的置疑之后
决定我应该弄一个三角挂挂
不好意思,太菜了

#44


设计模式!

#45


看来这个帖子还没结,我也进来看看热闹,同时表示对 阿扁为人的 认可

#46


看来这个帖挂在上面也没什么意思了。
现在 CSDN 的人气(以及人气的质量)真的不能跟一年前比了。

尽管我还没开始动手写这部分的代码,但基本方略也是有了。
基本上还是参照有些朋友建议的 SharpDevelop 的源代码。

不过,这个源代码的确很难读,关键是这个源代码不能用 VS.NET 来读(要想迁移到 VS.NET也很难)。我花了不少力气,终于读懂了大半,也知道了哪些可以借用,哪些不适合的应该去除。

如果真的用 SharpDevelop 来开发真正的应用,我和项目都会趴下的(个人能力所致)。


重点感谢以下朋友:
 haiwangstar(南河三(来自于小犬星座)) 
 idiotzeng(白痴) 
 IMarksman(唉!为什么总是睡不醒呢?) 
 aboush(无人居)
 Jim3(Jim) 
 cocosoft(pengyun)
 brightheroes(闭关|特别想砍暗黑......) 


等我目前手上的活儿忙完了,我马上会做这部分。做好了,我会另开帖或者发表一篇专题与大家分享我的实现。

最后加分结帖,可惜我只能加到 200 分。

#47


另外特别致谢:
 chestnuts(c# Sharp)

尽管我个人认为你的观点是偏激的,且略带有一些挑战性。
但你对本帖态度是认真的,而我个人认为这一点也是很重要的。

大家都素昧谋面,但宽容与和气是必须的,尽管争论可以面红耳赤。

#48


这么看中那个星是什么意思

我到是想请教AhBian (阿扁) 兄几个问题

不能说请教 
是请指点
我也在做类似的一个东西
只是现在没有什么明确的思路不知道该如何下手
能否把你的代码给我SEESEE
tianyamoon010@163.com