开发设计模式(二) ActiveObject模式

ActiveObject模式:

ActiveObject模式和Command模式的配合使用是实现多线程控制的一项古老的技术,该模式有多种使用方式,为许多工业系统提供了一个简单的多任务核心。 

// 活动对象的工具类,封装添加命令的方法以及运行方法

class ActiveObjectEngine
{
    ArrayList itsCommands = new ArrayList();
    // 添加命令 //
    public void AddCommand(Command c)
    {
        itsCommands.Add(c);
    }
    // 运行命令,并且移除 //
    public void Run()
    {
        while (itsCommands.Count > 0)
        {
            Command c = (Command)itsCommands[0];
            itsCommands.RemoveAt(0);
            c.Execute();
        }
    }
}

Run()函数只是遍历列表,执行并移除每个命令。如此,似乎也没给人很深刻的印象,但是发挥一下想象,如果链表中的command对象会克隆自己并把克隆对象放到链表的尾部,会是什么情况?可见这个链表不会为空,Run()永远不会返回。

// 唤醒命令,类似于undo()函数 //
class WakeUpCommand : Command
{
 public bool executed = false;
 public void Execute()
 {
  executed = true;
 }
}
// 睡眠命令 //
class SleepCommand : Command
{
    private Command wakeupCommand = null;
    private ActiveObjectEngine engine = null;
    private long sleepTime = 0;
    private System.DateTime startTime;
    private bool started = false;

    public SleepCommand(long milliseconds, ActiveObjectEngine e,Command wakeupCommand)
    {
        sleepTime = milliseconds;
        engine = e;
        this.wakeupCommand = wakeupCommand;
    }
    public void Execute()
    {
        System.DateTime current = DateTime.Now;
        if (!started)
        {
            Debug.Log("one..................add this");
            started = true;
            startTime = current;
            engine.AddCommand(this);
        }
        else
        {
            TimeSpan elapsedTime = current - startTime;
            Debug.Log("__" + elapsedTime.TotalMilliseconds);
            if (elapsedTime.TotalMilliseconds < sleepTime)
            {
                engine.AddCommand(this);
                Debug.Log("..................add this");
            }
            else
            {
                engine.AddCommand(wakeupCommand);
                Debug.Log("..................add wakeup");
            }
        }
    }
}

可见它的构造方法有三个参数,第一个是延迟时间,第二个是活动对象的工具类,第三个是唤醒命令类,分析代码可以看出,当前时间小于延迟时间的时候,会重复的调用自身(sleepCommand)的excute(),当大于延迟时间,就调用wakeupCommand,表示任务处理结束。

然后调用以上代码:

// 这里测试环境是unity3d,所以会看到Start()函数 
    void Start () {
        WakeUpCommand wakeup = new WakeUpCommand();
        ActiveObjectEngine e = new ActiveObjectEngine();
        SleepCommand c = new SleepCommand(900, e, wakeup);
        e.AddCommand(c);
        DateTime start = DateTime.Now;
        e.Run();

        DateTime stop = DateTime.Now;
        TimeSpan sleepTime = stop - start;

        print("command end:" + wakeup.executed + "  run time:" + sleepTime.TotalMilliseconds);
    }

打印的结果,wakeup.executed : true, 运行时间是一个大于900毫秒的数。

我们可以将该程序和等待一个事件的多线程程序做一个对比,多线程程序等待的时候,通常是使用操作系统调用来阻塞自己直到事件发生。

而上面的代码并没有阻塞,采用该技术的变体实现多线程是一个很优秀的方式,这种类型的线程称为run-to-completion任务(RTC),它的优点就是共享同一个运行时栈。这在需要大量线程的内存受限系统中是一个强大的优势。

以下代码是一个多线程的实例

class DelayedTyper : Command
{
    private long itsDelay;
    private char itsChar;
    private static bool stop = false;
    private static ActiveObjectEngine engine = new ActiveObjectEngine();

    class StopCommand : Command
    {
        public void Execute()
        {
            DelayedTyper.stop = true;
        }
    }
    public DelayedTyper(long delay, char c)
    {
        itsDelay = delay;
        itsChar = c;
    }

    public void Execute()
    {
        Debug.Log(itsChar);
        if (!stop)
        {
            DelayAndRepeat();
        }
    }
    public void DelayAndRepeat()
    {
        engine.AddCommand(new SleepCommand(itsDelay, engine, this));
    }

    public static void Go()
    {
        engine.AddCommand(new DelayedTyper(100, '1'));
        engine.AddCommand(new DelayedTyper(300, '3'));
        engine.AddCommand(new DelayedTyper(500, '5'));
        engine.AddCommand(new DelayedTyper(700, '7'));

        Command stopCommand = new StopCommand();
        engine.AddCommand(new SleepCommand(2000, engine, stopCommand));
        engine.Run();
    }
}

在Start函数添加:

DelayedTyper.Go();

打印的结果可以看出,每次的都会不一样,这是因为CPU的时钟和实时时钟没有完美的同步这种不确定的行为不就是多线程系统的特点么。

原文地址:https://www.cnblogs.com/martianzone/p/3361679.html