Scala设计模式
13-10-14
banq
Design Patterns in Scala一文列举了Java和Scala实现经典GoF设计模式的不同代码,有助于对比两种语言。
工厂模式:
Java代码:
Scala的代码:
注意Scala使用了trait替代Java接口,使用Object替代Java的Class。
Lazy initialization懒初始化
懒初始化是懒赋值lazy evaluation的一种特殊实现。
Java代码:
Scala代码:
Scala引入了lazy语法。
单态Singleton
Java代码:
Scala代码:
object语法其实是一个单例对象。
Adapter适配器
Java代码:
Scala代码:
Scala使用了语法implicit,隐式语法,它不是全局变量,也不是trait那样动态注入,隐藏魔法吧,在因果论中因有两种形式,显式因和隐式因,隐式因是无法显式看到的,所以new Logger还是之前原始类名,但是其实已经被调包。
Decorator适配器
Scala代码:
trait语法很适合进行方法拦截或添加。
工厂模式:
Java代码:
public interface Animal {} private class Dog implements Animal {} private class Cat implements Animal {} public class AnimalFactory { public static Animal createAnimal(String kind) { if ("cat".equals(kind)) return new Cat(); if ("dog".equals(kind)) return new Dog(); throw new IllegalArgumentException(); } } AnimalFactory.createAnimal("dog"); <p class="indent"> |
Scala的代码:
trait Animal private class Dog extends Animal private class Cat extends Animal object Animal { def apply(kind: String) = kind match { case "dog" => new Dog() case "cat" => new Cat() } } Animal("dog") <p class="indent"> |
注意Scala使用了trait替代Java接口,使用Object替代Java的Class。
Lazy initialization懒初始化
懒初始化是懒赋值lazy evaluation的一种特殊实现。
Java代码:
private volatile Component component; public Component getComponent() { Component result = component; if (result == null) { synchronized(this) { result = component; if (result == null) { component = result = new Component(); } } } return result; } <p class="indent"> |
Scala代码:
lazy val x = { print("(computing x) ") 42 } print("x = ") println(x) <p class="indent"> |
Scala引入了lazy语法。
单态Singleton
Java代码:
public class Cat implements Runnable { private static final Cat instance = new Cat(); private Cat() {} public void run() { // do nothing } public static Cat getInstance() { return instance; } } Cat.getInstance().run() <p class="indent"> |
Scala代码:
object Cat extends Runnable { def run() { // do nothing } } Cat.run() <p class="indent"> |
object语法其实是一个单例对象。
Adapter适配器
Java代码:
public interface Log { void warning(String message); void error(String message); } public final class Logger { void log(Level level, String message) { /* ... */ } } public class LoggerToLogAdapter implements Log { private final Logger logger; public LoggerToLogAdapter(Logger logger) { this.logger = logger; } public void warning(String message) { logger.log(WARNING, message); } public void error(String message) { logger.log(ERROR, message); } } Log log = new LoggerToLogAdapter(new Logger()); <p class="indent"> |
Scala代码:
trait Log { def warning(message: String) def error(message: String) } final class Logger { def log(level: Level, message: String) { /* ... */ } } implicit class LoggerToLogAdapter(logger: Logger) extends Log { def warning(message: String) { logger.log(WARNING, message) } def error(message: String) { logger.log(ERROR, message) } } val log: Log = new Logger() <p class="indent"> |
Scala使用了语法implicit,隐式语法,它不是全局变量,也不是trait那样动态注入,隐藏魔法吧,在因果论中因有两种形式,显式因和隐式因,隐式因是无法显式看到的,所以new Logger还是之前原始类名,但是其实已经被调包。
Decorator适配器
public interface OutputStream { void write(byte b); void write(byte[] b); } public class FileOutputStream implements OutputStream { /* ... */ } public abstract class OutputStreamDecorator implements OutputStream { protected final OutputStream delegate; protected OutputStreamDecorator(OutputStream delegate) { this.delegate = delegate; } public void write(byte b) { delegate.write(b); } public void write(byte[] b) { delegate.write(b); } } public class BufferedOutputStream extends OutputStreamDecorator { public BufferedOutputStream(OutputStream delegate) { super(delegate); } public void write(byte b) { // ... delegate.write(buffer) } } new BufferedOutputStream(new FileOutputStream("foo.txt")) <p class="indent"> |
Scala代码:
trait OutputStream { def write(b: Byte) def write(b: Array[Byte]) } class FileOutputStream(path: String) extends OutputStream { /* ... */ } trait Buffering extends OutputStream { abstract override def write(b: Byte) { // ... super.write(buffer) } } new FileOutputStream("foo.txt") with Buffering <p class="indent"> |
trait语法很适合进行方法拦截或添加。
banq
2013-10-14 08:56
值对象valueObject
值对象代表不可变,不变性,一旦构成就再也不改变。值对象是作为DTO的自然实现。
Java代码需要使用final
Scala主要针对可变和不可变提供var和val两个声明:
val point = (1, 2)
或
type Point = (Int, Int) // Tuple2[Int, Int]
val point: Point = (1, 2)
或
case class Point(x: Int, y: Int)
val point = Point(1, 2)
Null Object空对象
空对象代表一个对象什么也不做。
Java代码:
使用空对象就不必检查getSound()是否为空,
scala代码:
Scala使用Option。它可以用来作为一个可选值的占位符。
Strategy策略模式
Java代码:
Scala利用其函数语言的魔力简化了这些方法:
Command命令模式
java代码:
Scala使用by-name parameter 实现:
个人感觉,虽然很简单,大道至简,但是简单得有点像魔术,属于玄了。
Chain of responsibility职责链
Scala代码:
使用trait 和with语法替代了Java的"."
值对象代表不可变,不变性,一旦构成就再也不改变。值对象是作为DTO的自然实现。
Java代码需要使用final
public class Point { private final int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public boolean equals(Object o) { // ... return x == that.x && y == that.y; } public int hashCode() { return 31 * x + y; } public String toString() { return String.format("Point(%d, %d)", x, y); } } Point point = new Point(1, 2) <p class="indent"> |
Scala主要针对可变和不可变提供var和val两个声明:
val point = (1, 2)
或
type Point = (Int, Int) // Tuple2[Int, Int]
val point: Point = (1, 2)
或
case class Point(x: Int, y: Int)
val point = Point(1, 2)
Null Object空对象
空对象代表一个对象什么也不做。
Java代码:
public interface Sound { void play(); } public class Music implements Sound { public void play() { /* ... */ } } public class NullSound implements Sound { public void play() {} } public class SoundSource { public static Sound getSound() { return available ? music : new NullSound(); } } SoundSource.getSound().play(); <p class="indent"> |
使用空对象就不必检查getSound()是否为空,
scala代码:
trait Sound { def play() } class Music extends Sound { def play() { /* ... */ } } object SoundSource { def getSound: Option[Sound] = if (available) Some(music) else None } for (sound <- SoundSource.getSound) { sound.play() } <p class="indent"> |
Scala使用Option。它可以用来作为一个可选值的占位符。
Strategy策略模式
Java代码:
public interface Strategy { int compute(int a, int b); } public class Add implements Strategy { public int compute(int a, int b) { return a + b; } } public class Multiply implements Strategy { public int compute(int a, int b) { return a * b; } } public class Context { private final Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void use(int a, int b) { strategy.compute(a, b); } } new Context(new Multiply()).use(2, 3); <p class="indent"> |
Scala利用其函数语言的魔力简化了这些方法:
type Strategy = (Int, Int) => Int class Context(computer: Strategy) { def use(a: Int, b: Int) { computer(a, b) } } val add: Strategy = _ + _ val multiply: Strategy = _ * _ new Context(multiply).use(2, 3) <p class="indent"> |
Command命令模式
java代码:
public class PrintCommand implements Runnable { private final String s; PrintCommand(String s) { this.s = s; } public void run() { System.out.println(s); } } public class Invoker { private final List<Runnable> history = new ArrayList<>(); void invoke(Runnable command) { command.run(); history.add(command); } } Invoker invoker = new Invoker(); invoker.invoke(new PrintCommand("foo")); invoker.invoke(new PrintCommand("bar")); <p class="indent"> |
Scala使用by-name parameter 实现:
object Invoker { private var history: Seq[() => Unit] = Seq.empty def invoke(command: => Unit) { // by-name parameter command history :+= command _ } } Invoker.invoke(println("foo")) Invoker.invoke { println("bar 1") println("bar 2") } <p class="indent"> |
个人感觉,虽然很简单,大道至简,但是简单得有点像魔术,属于玄了。
Chain of responsibility职责链
Scala代码:
rait EventHandler { def handle(event: Event) } class DefaultHandler extends EventHandler { def handle(event: Event) { /* ... */ } } trait KeyboardHandler extends EventHandler { abstract override def handle(event: Event) { if (event.source == "keyboard") /* ... */ else super.handle(event) } } trait MouseHandler extends EventHandler { abstract override def handle(event: Event) { if (event.source == "mouse") /* ... */ else super.handle(event) } } new DefaultHandler with KeyboardHandler with MouseHandler <p class="indent"> |
使用trait 和with语法替代了Java的"."
banq
2013-10-14 09:02
Dependency injection依赖注入
Java代码:
java实现注入需要依赖Spring或JEE之类框架容器,而Scala好像不像之前显得那么从容,这点在发明语言时怎么没有考虑呢?依赖注入大概是针对类的,而不是函数。
更多见 Cake pattern :Real-World Scala: Dependency Injection (DI)
Java代码:
interface Repository { void save(User user); } class DatabaseRepository implements Repository { /* ... */ } class UserService { private final Repository repository; UserService(Repository repository) { this.repository = repository; } void create(User user) { // ... repository.save(user); } } new UserService(new DatabaseRepository()); <p class="indent"> |
java实现注入需要依赖Spring或JEE之类框架容器,而Scala好像不像之前显得那么从容,这点在发明语言时怎么没有考虑呢?依赖注入大概是针对类的,而不是函数。
trait Repository { def save(user: User) } trait DatabaseRepository extends Repository { /* ... */ } trait UserService { self: Repository => // requires Repository def create(user: User) { // ... save(user) } } new UserService with DatabaseRepository <p class="indent"> |
更多见 Cake pattern :Real-World Scala: Dependency Injection (DI)
lshoo
2013-10-17 08:21
Scala本身的语言特性比Java要强大很多,很多Java的设计模式用Scala就不存在了。
例如DI,Scala的cake pattern, function currying,implicit等实现起来都委优雅。
例如DI,Scala的cake pattern, function currying,implicit等实现起来都委优雅。
[该贴被lshoo于2013-10-17 08:58修改过]