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

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

开发设计模式(⼆)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的时钟和实时时钟没有完美的同步,这种不确定的⾏为不就是多线程系统的特点么。

相关文档
最新文档