Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1503983
  • 博文数量: 3500
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 43870
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-03 20:31
文章分类

全部博文(3500)

文章存档

2008年(3500)

我的朋友

分类:

2008-05-04 20:52:59

一起学习

在当前软件设计中最流行的要算GoF这本书中提出的各种设计模式。很多人认为,设计模式对于程序语言(特别是c /Java)本身的不足之处或多或少有一些弥补,不过如果语言足够强大,模式也许没有必要。

下面Peter Norvig的一个例子就非常有代表性。在有些语言中,使用设计模式在使代码变得自然和简洁,但是模式本身使用方便性也很重要。不妨让我们来看看Scala(一种类似Ruby/Lisp之类的语言,它一定程度上降低了模式实现的繁琐)中常用的一些模式。

1.Singleton(单体模式)

单体模式是一种非常频繁使用到的模式。尽管它是一种最简单的模式,而要在Java语言中实现的纯粹的单体模式却是异常困难。尤其是涉及到著名的double-checked locking 等问题。然而,对于Scala语言,一点也不难。可以说,你只是需要创建一个单体模式的Registry对象。按下面步骤:
object Registry {
def getEntry(): Entry {
}
//Other fields/methods
}
//Create and use the singleton
val entry = Registry.getEntry

这样就行了,唯一的区别是定义一个普通类时使用关键词‘object’而不是‘class’。如果你需要映射回到Java语言,只需要定义一个所有域/方法都是static的类。

2.Strategy(策略模式)


对于把函数功能用一组对象来实现或者带有截止功能的语言来说,策略模式是一个明显的选择。下面以‘征税’为例:

trait TaxPayer
case class Employee(sal: Long) extends TaxPayer
case class NonProfitOrg(funds: BigInt) extends TaxPayer

//Consider a generic tax calculation function. (It can be in TaxPayer also).
def calculateTax[T <: TaxPayer](victim: T, taxingStrategy: (T => long)) = {
taxingStrategy(victim)
}

val employee = new Employee(1000)
//A strategy to calculate tax for employees
def empStrategy(e: Employee) = Math.ceil(e.sal * .3) toLong
calculateTax(employee, empStrategy)

val npo = new NonProfitOrg(100000000)
//The tax calculation strategy for npo is trivial, so we can inline it
calculateTax(nonProfit, ((t: TaxPayer) => 0)

3.Factory(工厂模式)

工厂模式是针对那种对象构造函数不能返回仲裁对象的情况的。 如果你调用对象A的构造函数生成对象,

你得到的是一个对象A。如果你需要其它不同类型的对象,一般创建一个单体工厂。在Scala语言中你也要做这样的事,但是实现的方式更为优雅:

object Car {
def apply(String type) {
type match {
case "Race" => new RaceCar();
case "Normal" => new NormalCar();
case _ => throw new Exception;
}
}
}
//And you can create cars like:
val myCar = Car("Race")
//instead of more verbose
//Car myCar = CarFactory.getInstance().createCar("Ferrari");
基本上,这样你可以利用这个方式,看起来就像一个构造函数调用一个单体对象。

4.Vistor(访问者模式)

访问者模式被许多人认为是有害的,但是它有自己的价值。让我们来看看在Java中典型的使用访问者模式的例子:

abstract class Expression {
...
public void accept(Visitor v);
}

class Identifier extends Expression {
}
class Sum extends Expression {
}
..

class Visitor {
public void visit(Identifier i) { }
public void visit(Sum s) { }
}


典型的Java样本代码如你所熟悉的那样。在Scala语言中,利用模式匹配你可以达到同样的效果:
trait Expression {
...
}

case class Identifier(value: Int) extends Expression {
}
case class Sum extends Expression {
}

object EvalVisitor {
def visit(expr: Expression): Int = expr match {
case (Identifier(v)) => v
case (Sum(e1, e2)) => visit(e1) visit(e2)
}
}

但是这种模式匹配的代码具有更大的灵活性。

5.Decorator(装饰模式)

最后来看一下装饰模式,既然Scala支持mixins和隐式转换,装饰模式也是简单和自然的。在概念上,有两个途径可以用来给一个对象加入新的功能以扩展现有功能。你可以使用隐式转换,也考虑使用Scala的标准库中的RichInt类,只需要下面的操作:

val range1to10 = 1 to 10
在Scala语言中是调用to把1转换为10。但是在Int类中没有to方法。它怎么处理呢? Scala公司有一个新的概念叫做implicits,来调用你的库。某种程度上,这其实是Ruby的公开类。这是个有趣的事,你可以在任意地方读取它。对我们来说,这里预先包含了一个隐式的转换。Mixins也可以很好的扩展你的类功能。下面考虑一个典型的阅读方面的接口:

trait Reader {
type T
def read: T
}

trait SynchronizedReader extends Reader {
abstract override def read: T = synchronized(super.next)
}

trait BufferedReader extends Reader {
abstract override def read: T = {
//buffering code
super.read
}
}

//A concrete implementation
class FileReader extends Reader {
type T = char
def read: char = ..
}

//Now we can mix in stuff that we need
//Create a FileReader
val f = new FileReader
//create a fileReader which is synchronized
val syncReader = new FileReader with SynchronizedReader
//create a fileReader which is synchronized and buffered
val bsReader = new FileReader with BufferedReader with SynchronizedReader

结论
设计模式是软件设计中很有用的一种指导方式。但是,大部分模式只是解决语言本身的问题,而不是关于设计方面的。要是你有一个好的语言方式,那么大部分的模式将变得无足轻重。比如,一个结构化的语言,虚方法和虚类的概念也是一种设计模式。如果你使用一种足够强大的语言,你需要的设计方式也会更高级。随着发展,它们越将演变为一种更高层次的抽象。

下载本文示例代码


Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式Scala和设计模式
阅读(187) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~