• WF本质论 读书心得 1 剖析WF (上)


    如果没有微软的WF,如何设计一个自己的工作流,本章通过经典的芝麻开门(OpenSesame)示例,向读者展示了WF基本的设计思路.
    这一章我读了很多遍才想明白.建议所有读者在阅读后续章节时,一定要先读懂本章,这是全书的基石;还有就是本章的示例代码并不完整,仅仅是一个类及其方法的骨架,也是容易使人困惑的.

    设计交互式WF,要解决两个问题:
        1.线程阻塞,比如说Console.ReadLine这样的语句, 因此有必要将其设计为异步方法BeginReadLine与EndReadLine,如下:

        public static System.IAsyncResult BeginReadLine(System.AsyncCallback asyncCallback, object state);
        
        
    public static string EndReadLine(System.IAsyncResult ar);

            使用如下, 注意到变量key实现了跨线程共享:

            static string key;

            
    public static void Main()
            
    {
                key 
    = "xxx";
            
                BeginReadLine(ContinueAt, 
    null);
                
                Thread.Sleep(Timeout.Infinite);
            }

            
            
    static void ContinueAt(IAsyncResult ar)
            
    {
                
    string s = EndReadLine(ar);
                
                
    if(key == s){}
            }

             不仅仅是ReadLine方法,所有阻塞线程的方法都可以一拆为二,并按照上述原则进行操作

        2.进程闲置
            闲置的进程可以序列化到外部,这个技术称为钝化passivate;需要的时候再进行恢复,恢复点称为书签Bookmark,程序上表现为delegate.
            钝化可以彻底消除对栈的依赖.
            Bookmark实体类设计如下:

    注意, Name是key, Payload是异步调用时需要的参数,BookmarkLocation是一个委托,BookmarkManager用于指定当前Bookmark的管理器.

    BookmarkManager是一个书签管理器,具体实现如下(书中省略了):

        public class BookmarkManager
        
    {
            
    private List<Bookmark> bookmarkList;

            
    public BookmarkManager()
            
    {
                bookmarkList 
    = new List<Bookmark>();
            }


            
    public void Add(Bookmark bookmark)
            
    {
                bookmarkList.Add(bookmark);
                bookmark.BookmarkManager 
    = this;
            }


            
    public void Remove(Bookmark bookmark)
            
    {
                bookmarkList.Remove(bookmark);
            }


            
    public void Resume(string bookmarkName, object payload)
            
    {
                
    foreach (Bookmark bookmark in bookmarkList)
                
    {
                    
    if (bookmark.Name == bookmarkName)
                    
    {
                        bookmark.Payload 
    = payload;
                        bookmark.BookmarkLocation(bookmark);

                        
    break;
                    }

                }

            }

        }

    对于逻辑类OpenSesame的实现,要求有一个全局变量key和一个异步方法ContinueAt,这是为了解决线程阻塞,上文已经述及其意图;此外Start()方法也是必须的,用于初始化书签管理器并将自身加入其中,最后这个类还要标明[Serializable]

    于是Main()方法的实现如下:

            static void Main(string[] args)
            
    {
                BookmarkManager mgr 
    = new BookmarkManager();
                OpenSesame openSesameProgram 
    = new OpenSesame();
                openSesameProgram.Start(mgr);


                
    string str = Console.ReadLine();
                mgr.Resume(
    "read", str);

                Console.ReadLine();
            }

    至此,一个WF Sample完美实现,仅包括一个Sesame逻辑的一个实例。

    接下来要考虑多个逻辑多个实例的实现:使用运行时Runtime进行管理
    于是建立ProgramStatement抽象基类,所有逻辑类(如OpenSesame)都派生于此,其中Run()方法就是OpenSesame的Start()方法。我们称之为可恢复语句组件。
    同时,建立MythicalRuntime类和PrograHandle类,进行更高层次的包装。

    从而,Main()方法的实现可以如下:

                MythicalRuntime runtime = new MythicalRuntime();

                
    while (true)
                
    {
                    Guid guid 
    = "Your passive guid";
                    ProgramHandle handle 
    = runtime.GetProgramHandle(guid);

                    
    string bookmarkName = "Jax";
                    
    object input = "XXXXXX";
                    handle.Resume(bookmarkName, input);
                }

    注意,这段代码的功能仅仅是根据input进行恢复,并没有事先设置初始值,我们只要看清大致思路即可。
    MythicalRuntime类和ProgramHandle类,书中省略了代码,我自己的实现如下:

        public class MythicalRuntime
        
    {
            Dictionary
    <ProgramHandle, ProgramStatement> ht;

            
    public MythicalRuntime()
            
    {
                ht 
    = new Dictionary<ProgramHandle, ProgramStatement>();
            }


            
    public ProgramHandle RunProgram(ProgramStatement program)
            
    {
                
    //这个新的Guid根据规则创建,而不是简单的new Guid(),以下仅为模拟方法
                Guid programId = new Guid();

                ProgramHandle programHandle 
    = new ProgramHandle();
                programHandle.ProgramId 
    = programId;

                ht.Add(programHandle, program);

                
    return programHandle;
            }


            
    public ProgramHandle GetProgramHandle(Guid programId)
            
    {
                
    //根据programId恢复已经钝化的程序,假设恢复为OpenSesame方法
                ProgramStatement program = new OpenSesame();

                
    //重新构建ProgramHandle
                ProgramHandle programHandle = new ProgramHandle();
                programHandle.ProgramId 
    = programId;

                
    //重新加载到内存
                ht.Add(programHandle, program);

                
    return programHandle;
            }


            
    public void Shutdown()
            
    {
                
    //从内存中取出所有ProgramHandle, 依次钝化
                foreach (ProgramHandle tmpProgramHandle in ht.Keys)
                
    {
                    ProgramStatement program 
    = ht[tmpProgramHandle];
                    tmpProgramHandle.Passivate(program);
                }


                ht 
    = null;
            }

        }


        
    public class ProgramHandle
        
    {
            
    private Guid programId;

            
    public Guid ProgramId
            
    {
                
    get return programId; }
                
    set { programId = value; }
            }


            
    public void Passivate(ProgramStatement program)
            
    {
                
    //将program根据关键字programId进行钝化
            }


            
    public void Resume(string bookmarkName, object payload)
            
    {
                BookmarkManager mgr 
    = new BookmarkManager();
                mgr.Resume(bookmarkName, payload);
            }

        }

    根据我的理解,做出如下修正:
    1.在MythicalRuntime类中添加泛型ht,建立了ProgramHandle与ProgramStatement的一一映射。
    2.RunProgram专门用于在内存中创建新程序。
    3.ProgramHandle类的Passivate()方法,增加方法参数后为:
        public void passive(ProgramStatement program);
        从而将programId和相应的ProgramStatement一起存储。


    *本章的页眉都写错了,应该把"部"改为"剖",建议译者下一版时修正.

  • 相关阅读:
    Python正课15 —— 流程控制之while循环
    Python正课14 —— 深浅Copy
    Python正课13 —— 流程控制之if判断
    Python正课12 —— 成员运算 与 身份运算
    Python正课11 —— 逻辑运算
    Python正课10 —— 条件
    Python正课9 —— 可变不可变类型
    Python正课8 —— 运算符
    Python正课7 —— 与用户交互
    Python正课6 —— 垃圾回收机制
  • 原文地址:https://www.cnblogs.com/Jax/p/1076632.html
Copyright © 2020-2023  润新知