hans.hu

夫天地者,万物之逆旅也;光阴者,百代之过客也。而浮生若梦,为欢几何?古人秉烛夜游,良有以也。况阳春召我以烟景,大块假我以文章。

从一个小实例开始 - Boo开篇

前一阵小组内部培训时,提到下面这个例子:
“假设我们有个高档的热水器,我们给它通上电,当水温超过95度的时候:
1、警报器会开始发出语音,告诉你水的温度;
2、显示器也会改变水温的显示,提示水已经快烧开了。 ”

相信大家能很快明白这是GoF设计模式中典型的Observer模式,下面我想通过这个例子用Boo实现来作为Boo系列的开篇。

在继续之前,为了方便大家看到C#与Boo两者在语法上的不同,我先写出C#下Observer模式的实现(采用事件机制):

#region C# Observer Pattern
public delegate void NotifyEventHandler(Heater heater);

public class Heater
{
    public event NotifyEventHandler Notify = delegate { };
    public int Temperature {
        get;
        set;
    }
    public void Boil() {
        if (Temperature > 95)
            Notify(this);
    }
}

public abstract class Device
{
    public virtual void Update(Heater heater) {
        Do();
        Console.WriteLine("The water is boiling! Water temperature is {0}", heater.Temperature);
    }
    protected abstract void Do();
}
public class Alarm : Device
{
    protected override void Do() {
        Console.WriteLine("Alarm!");
    }
}
public class Monitor : Device
{
    protected override void Do() {
        Console.WriteLine("Monitor!");
    }
}
#endregion

这里我暂且不介绍Boo,而是直接给出Boo版本下的Observer模式:

namespace Observer
import System
// Boo Observer Pattern
//callable NotifyEventHandler(heater as Heater);
class Heater:
 //event Notify as NotifyEventHandler
 event Notify as callable(object)
 
 [Property(Temperature)]
 _temperature as int
 
 def Boil():
//  if Temperature > 95:
//   Notify(self)
  Notify(self) if Temperature > 95 // Equivalent of the above
//
abstract class Device:
 virtual def Update(heater as Heater):
  Do()
  print "The water is boiling! Water temperature is ${heater.Temperature}."
 abstract def Do():
  pass

class Alarm(Device):
 override def Do():
  print "Alarm!"
class Monitor(Device):
 override def Do():
  print "Monitor!" 
//
heater = Heater(Temperature:98)
alarm = Alarm()
monitor = Monitor()
//heater.Notify += def(heater as Heater):
// print heater.Temperature
heater.Notify += alarm.Update
heater.Notify += monitor.Update

heater.Boil()

Console.ReadKey()

Boo是一个类似Python语法、静态类型、运行在CLR之上的面向对象语言。它有一个强大的编译器扩展能力和更容易构建DSL的特性,目前Boo主要应用在DSL上。

Boo的编译器扩展性意味着你可以对编译器进行自定义的扩展,使你能够在编译器层次上对Boo进行加强,这也使得Boo非常适合于DSL的编写。Boo编译器允许你直接与Pipeline管道交互,Boo编译器管道由一系列的Compiler steps组成,每个Compiler Step都可以与解析后的代码交互从而改变其AST(Abstract Syntax Tree),最终AST会生成.NET程序集代码(IL)。

大家可以看看大师Ayende Rahien使用Boo写的例子,大家可以感受到Boo语言的灵活与强大:

namespace BSDLiB

import System
import System.Xml
import System.Threading
import AstModifications
import AstModifications.MetaMethods
import AstModifications.SLA
import AstModifications.SLA.MyExtensions

import Boo.Lang.Compiler.Ast

unroll i, 5:
 print i
 
unroll2 i, 5:
 print i 

print "Using XML OBject"
print " - - - - - - - - - "
xml = """
<People>
 <Person>
  <FirstName>John</FirstName>
 </Person>
 <Person>
  <FirstName>Jane</FirstName>
 </Person>
</People>
"""

xmlDocument = XmlDocument()
xmlDocument.LoadXml(xml)

doc = XmlObject(xmlDocument.DocumentElement)
for person as XmlObject in doc.Person:
 print person.FirstName

print " - - - - - - - - - "
print "Using meta methods"
print " - - - - - - - - - "
# Using Meta Methods
try:
 verify 1 == 2
except e:
 print e
 
# Using macros
print " - - - - - - - - - "
print "Using Macros"
print " - - - - - - - - - "
limitedTo 200.ms:
   Thread.Sleep(201)
   whenExceeded:
            print "Took more than 200 ms!"


#using AST Attributes
print " - - - - - - - - - "
print "Using AST Attributes"
print " - - - - - - - - - "
customer = Customer("test")

try:
 customer.SetName(null)
except e:
 print e

【注】:
1, unroll/unroll2
是Boo中的Macro,用两种不同的方式实现了Macro。Boo中的Macro允许我们后期通过[macro name]来引用宏代码。
2, XmlObject
是实现了IQuackFu接口的类,IQuackFu接口可以让类自己负责方法、属性的调用,非常适合处理“Missing Method”的问题。
3, verify
Meta方法,标记了Meta属性的静态方法可以很容易对AST节点进行操作(Static methods tagged with the Meta attribute should be perceived as a shortcut to the compiler that accepts AST (Abstract Syntax Tree) Nodes and returns an AST node.),这个特性使之很容易创建新的keywords。
4, limitedTo
较复杂的Macro使用:两个Macro之间的交互、Extension的使用。

例子中的具体特性以后我会慢慢向大家讲解,这里只是展示一下Boo的强大扩展性。

借助于Boo所内建的语言特性以及简单的语法结构,加上其静态特性,我们可以用该语言更加高效地编写.NET应用程序。另外,在Boo中,我们还可以使用任何CLI平台上的现存类库,Boo代码同样能够容易地在其他CLI语言中被重用!稍后我会分几部分来详细介绍Boo语言以及其在C#中的使用(DSL方面)。

最后,顺便也试试把JavaScript版本的Observer写出来:

// JavaScript Observer Pattern
function Heater(t) {
    this.Temperature = t;
}
Heater.prototype = {
    Notify: function() {
        if (this.events) {
            if (this.Temperature > 95) {
                for (var i = 0; i < this.events.length; i++)
                    this.events[i].Update();
            }
        }
    },
    Attach: function(handler) {
        if (!this.events) this.events = [];
        this.events.push(handler);
    }
}
// Base class
var Device = {
    Initialize: function(name) {
        this.Name = name;
    },
    Update: function() {
        alert(this.Name);
    }
}
// subclasses
function Alarm(name) {
    Device.Initialize.call(this, name);
}
Alarm.prototype = Device;

function Monitor(name) {
    Device.Initialize.call(this, name);
}
Monitor.prototype = Device;

// The example
var alarm = new Alarm("Alarm");
var monitor = new Monitor("Monitor");
var heater = new Heater(98);

heater.Attach(alarm);
heater.Attach(monitor);

heater.Notify();

大家有兴趣可以参考下面链接看看Boo的介绍,这会增加对Boo的认识很有帮助,稍后我会分几个部分循序渐进地向大家展现Boo的魅力,希望能有更多的人关注Boo,大家一起学习使用:
Boo Website
The Boo extensibility tutorials
Ayende Rahien - Boo
在CLR之上的构建领域特定语言
概览CLI之上的新语言 - Boo

posted on 2009-04-14 11:41  hans.hu  阅读(3206)  评论(10编辑  收藏  举报

导航