Design Patterns in Scala
This article shows how Scala adopts and transforms the classical software design patterns.
The content of the article is also (independently) translated into Russian and Chinese.
Design pattern is a general reusable solution to a commonly occurring problem in software design. A design pattern is not a finished code, but rather a template for how to solve a problem that can be used in many different situations.
Patterns are formalized best practices of effective design, which helps to prevent subtle issues, improve code readability and speed up the development process.
The classical design patterns (mostly, the GoF patterns) are object-oriented. They show relationships and interactions between classes and objects. These patterns are less applicable in pure functional programming (see Haskell’s Typeclassopedia and Scalaz for “functional” design patterns, kind of), however, since Scala is an object-functional hybrid language, these patterns are still very relevant, even in “functional” Scala code.
Sometimes, design patterns may be a sign of some missing feature in a programming language. In such cases, the patterns might be simplified or eliminated when a programming language provides the required features. In Scala, it’s possible to implement most classical design patterns directly, relying on the expressive language syntax.
While Scala may employ additional, language-specific design patterns, this article focuses on the well-known, classical patterns, because these patterns also serve as the means of communication between developers.
Sure we can use the Force all the power of Scala to completely transcend all these patterns, but in this article I intentionally tried to avoid more advanced techniques in favor of more simple and pictorial ones, in order to provide a clean mapping between languages.
Creational patterns:
Structural patterns:
Behavioral patterns:
So, here goes the patterns (all the code is available as a GitHub repository).
Factory method
The factory method pattern provides an interface for creating an object that encapsulates the actual class instantiation in a method, and lets subclasses decide which class to instantiate.
Factory method allows to:
- merge complex object creation code,
- select which class to instantiate,
- cache objects,
- coordinate access to shared resources.
We will consider the static factory method, which is slightly different from the classical version of the pattern – static factory method avoids subclassing, so there’s no option to override the method.
In Java, we use new operator to instantiate a class, by invoking its constructor. To implement the pattern, we rely on ordinary methods. Also, because we can’t define static methods in interface, we have to use a separate factory class:
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");
In addition to constructors, Scala provides a special syntactic construct, that looks similar to constructor invocation, but it’s actually a convenient factory method:
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")
The factory method is defined in so-called “companion object” – a special singleton object with the same name, defined in the same source file. This syntax is limited to the static version of the pattern, because we cannot delegate object creation to subclasses.
- Reuses base class name.
- Standard and concise.
- Resembles constructor invocation.
- Static factory method.
Lazy initialization
Lazy initialization is a special case of lazy evaluation strategy. It’s a technique that initializes a value (or an object) on its first access.
Lazy initialization allows to defer (or avoid) some expensive computation.
A typical Java implementation uses null value to indicate uninitialized state. However, if null is a valid final value, then a separate flag is needed to indicate whether the initialization process has taken place.
In multi-threaded code, access to the flag must be synchronized to guard against a race condition. Efficient synchronization may employ double-checked locking, which complicates code even further:
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;
}
Scala offers a clean built-in syntax to define lazy values:
lazy val x = {
print("(computing x) ")
42
}
print("x = ")
println(x)
// x = (computing x) 42
Lazy values in Scala can hold null values. Access to lazy value is thread-safe.
- Concise syntax.
- Lazy values can hold nulls.
- Lazy values are thread-safe.
- Less control over initialization.
Singleton
The singleton pattern restricts the instantiation of a class to one object, and provides a global point of access to it.
Singleton is probably the most well-known design pattern in Java. It is a clear sign of the missing language feature.
While Java language includes static keyword, static members are not associated with any object, and static member classes cannot implement an interface. Thus, the concept of static methods in Java goes against the basic OOP premise that everything is an object. “Static members” is just a fancy new name for conventional subroutines.
So, when we need a globally accessible implementation of an interface (possibly, with lazy initialization), the Singleton pattern comes to the rescue:
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()
However, more advanced Singleton implementations (with lazy initialization) can be rather verbose or prone to subtle errors (e.g. double-checked locking).
Scala provides concise direct realization of the singleton pattern in the language:
object Cat extends Runnable {
def run() {
// do nothing
}
}
Cat.run()
Objects can inherit methods from classes or interfaces. Object can be referenced (directly or via an inherited interface). In Scala, objects are initialized on-demand.
- Clear intent.
- Concise syntax.
- On-demand initialization.
- Thread-safety.
- Less control over initialization.
Adapter
The adapter pattern converts interface of a class into expected interface, allowing classes with incompatible interfaces to work together.
Adapters are useful for integrating existing components.
Java implementation creates a wrapper class, that is explicitly used in the code:
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());
In Scala, we have a built-in concept of interface adapters, expressed as implicit classes:
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()
When expected type of expression is Log, yet a Logger instance is used, Scala compiler will automatically wrap that instance in the adapter class.
Another possible example of the Adapter pattern in Scala is typeclasses.
- Clear intent.
- Concise syntax.
- Might be obscure without IDE.
Decorator
The decorator pattern is used to extend functionality of some object, without affecting other instances of the same class. Decorators provide a flexible alternative to subclassing.
The decorator pattern is helpful when there are several independent ways of extending functionality, that can be arbitrarily combined together.
In Java, the goal is achieved by defining a new decorator class that inherits the base interface and wraps the original class, so that multiple decorators can be stacked on top of each other. An intermediate decorator class is often used to abstract the delegation of multiple methods:
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"))
To achieve the same goal, Scala provides a direct way of overriding interface methods, without binding to their concrete implementation in place of declaration. Here’s how we can use abstract override modifier:
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 // with Filtering, ...
The delegation is established statically, at compile time, but that’s usually enough as long as we can arbitrarily combine decorators in place of object creation.
As opposed to composition-based implementation, Scala’s approach preserves object identity, so we may safely use equals on decorated objects.
In Scala, such a use of traits is known as Stackable Trait Pattern.
- Clear intent.
- Concise syntax.
- Object identity is preserved.
- No explicit delegation.
- No intermediate decorator class.
- Static binding.
- No constructor parameters.
Value object
Value object is a small immutable object that represents a simple entity whose equality isn’t based on identity. Value objects are equal if all their fields are equal.
Value objects are widely used to represent numbers, dates, colors, etc. In enterprise applications they are used as DTOs a for inter-process communication. Because of the immutability, value objects are handy in multi-threaded programing.
in Java, there’s no special syntax for value objects, so we have to define (and update) a constructor, getters and auxiliary methods explicitly:
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)
In Scala, we can use either tuples or case classes to declare value objects. When a separate class is not needed, tuples is the way to go:
val point = (1, 2) // new Tuple2(1, 2)
Tuples are predefined immutable “collections” that can hold a fixed number of items of different types. Tuples provide constructor, getters, and all the auxiliary methods.
We may also create a type alias for our point representation, so we may use it in declarations:
type Point = (Int, Int) // Tuple2[Int, Int]
val point: Point = (1, 2)
When a dedicated class is required, or when we want more descriptive names for the data items, we may define a case class:
case class Point(x: Int, y: Int)
val point = Point(1, 2)
Case classes export constructor parameters as properties. By default, case classes are immutable. Like tuples, they provide all the required methods automatically. Because case classes are valid classes, the can use inheritance and define members.
Value object pattern is ubiquitous tool in functional programming (as a part of ADT concept), and Scala offers complete support for value objects directly in the language.
- Concise syntax.
- Predefined tuple classes.
- Built-in auxiliary methods.
- None.
Null Object
Null Object represents the absence of an object by defining a neutral, “do nothing” behavior.
This approach has an advantage over using null references, because there’s no need to explicitly check the validity of references before usage.
In Java we may implement the pattern by defining a special subclass with empty methods:
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();
So, we don’t need to check the reference returned form getSound method before calling play. Additionally, we may define the Null Object as Singleton to limit the number of “null-instances” to one.
Scala uses a similar approach, yet it provides a predefined Option type, which can be used as a placeholder for optional value:
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()
}
In this case, we use so-called “for comprehension” to process the optional value (higher-order functions and pattern matching are also suitable for that purpose).
- Predefined type.
- Explicit optionality.
- Works with built-in constructs.
- More verbose usage.
Strategy
The strategy pattern defines a family of encapsulated algorithms and lets the algorithm vary independently from clients that use it.
The pattern is handy when we need to select an algorithm at runtime.
In Java, strategy is usually implemented by creating a hierarchy of classes that inherit a base interface:
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);
Because Scala offers first-class functions, we can use them to express the same concept directly:
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)
When strategy consists of multiple methods, we may use a case class or a tuple to group these methods together.
- Concise syntax.
- General-purpose type.
Command
The command pattern is used to encapsulate all the information needed to call a method at a latter time. This information includes the method name, the object that owns the method and values for the method parameters.
The command is useful to delay, sequence or log method calls.
In Java, the goal is achieved by wrapping the call in an object:
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"));
In Scala, we can rely on by-name parameter to defer evaluation of any expression:
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")
}
That is how we can convert arbitrary expression or code block to a function object. The calls to the println method are evaluated withing the calls to invoke method, and then stored as functions in the history sequence.
We can also define functions directly, without resorting to by-name parameters, however that approach is a little bit more verbose.
- Concise syntax.
- General-purpose type.
Chain of responsibility
The chain of responsibility pattern decouples the sender of a request from its receiver, by giving more than one object an opportunity to handle the request. The request is processed by the chain until some object handles it.
In a typical implementation of the pattern every object in the chain inherits a base interface and contains an optional reference to a next processing object in the chain. Each object is given a chance to either handle the request (and interrupt the processing), or pass the request to the next handler in the chain. The sequencing logic can be either delegated to objects, or encapsulated in a base class:
public abstract class EventHandler {
private EventHandler next;
void setNext(EventHandler handler) { next = handler; }
public void handle(Event event) {
if (canHandle(event)) doHandle(event);
else if (next != null) next.handle(event);
}
abstract protected boolean canHandle(Event event);
abstract protected void doHandle(Event event);
}
public class KeyboardHandler extends EventHandler { // MouseHandler...
protected boolean canHandle(Event event) {
return "keyboard".equals(event.getSource());
}
protected void doHandle(Event event) { /* ... */ }
}
KeyboardHandler handler = new KeyboardHandler();
handler.setNext(new MouseHandler());
Because such an implementation is somewhat similar to the Decorator‘s one, we may use abstract override functionality to achieve the goal. However, Scala provides an even more straightforward approach, that is based on partial functions.
A partial function is a function that is defined only for a subset of the possible values of its arguments. While we may call isDefinedAt and apply on partial functions directly in order to implement the sequencing, the better way is to rely on the built-in orElse method for chaining:
case class Event(source: String)
type EventHandler = PartialFunction[Event, Unit]
val defaultHandler: EventHandler = PartialFunction(_ => ())
val keyboardHandler: EventHandler = {
case Event("keyboard") => /* ... */
}
def mouseHandler(delay: Int): EventHandler = {
case Event("mouse") => /* ... */
}
keyboardHandler.orElse(mouseHandler(100)).orElse(defaultHandler)
Note that we need to use the defaultHandler to avoid errors on “undefined” events.
- Concise syntax.
- Built-in logic.
- General-purpose type.
Dependency injection
The dependency injection (DI) pattern allows to avoid hard-coded dependencies and to substitute dependencies either at run-time or at compile time. The pattern is a special case of inversion of control (IoC) technique.
Dependency injection is used to choose among multiple implementations of a particular component in application, or to provide mock component implementations for unit testing.
Apart from IoC containers, the simplest Java implementation uses constructor arguments to pass required dependencies. So, we use composition to express dependency requirements:
public interface Repository {
void save(User user);
}
public class DatabaseRepository implements Repository { /* ... */ }
public class UserService {
private final Repository repository;
UserService(Repository repository) {
this.repository = repository;
}
void create(User user) {
// ...
repository.save(user);
}
}
new UserService(new DatabaseRepository());
In addition to composition (“HAS-A”) and inheritance (“IS-A”), Scala offers a special kind of object relation – requirement (“REQUIRES-A”), expressed as self-type annotations. Self-types let us specify additional type expectations for an object, without exposing them in the inheritance hierarchy.
We can use self-type annotations together with traits to implement dependency injection:
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
Unlike constructor injection, this approach requires a single reference for each kind of dependency in configuration. The full implementation of this technique is known as Cake pattern (and there are many other ways to implement DI in Scala).
Since mixing in traits is done statically in Scala, this approach is limited to compile-time dependency injection. However, in practice, run-time re-configuration is rarely needed, while static checking of configuration is a definite advantage (over an XML-based configuration).
- Clear intent.
- Concise syntax.
- Static checking.
- Compile-time configuration.
- Might be verbose.
Afterword
I hope that this demonstration helps to bridge the gap between the two languages, so that Java programmers can easily gain insight into Scala syntax, and Scala programmers can map the language-specific constructs into the well-known abstractions.
See also:
Thanks for sharing, nice good reminder of how great Scala is 🙂
Great writeup! I was missing the visitor pattern, and its Scala equivalent, pattern matching.
Hi Martin! I’m glad you like it, endorsement from the language creator is kind of, “official approval” 🙂 I’m planning to add the Visitor and the Builder patterns later, because there are already too many patterns for a single conference talk.
For the Null Object pattern in Scala, I will have used “sound foreach _.play()” instead of the for comprehension. A lot of Iterable methods work on Option, but only when is non-empty, so chaining them is safe. It reads a little bit strange (foreach? there is only one!) but it is more succinct.
Hi Daniel! That’s true. I mentioned that we may also use either higher-order functions or pattern matching for that purpose (and I actually prefer higher-order functions), however I used a for-comprehension in the example to emphasize the integration of Option with the built-in language syntax.
Great article, I like some of the solutions!
However, for the Factory pattern, I think that you could go even further with the Scala features and make it safer and easier to extend with new “Animals”. All this by using typeclasses: https://gist.github.com/Mortimerp9/6952000
There is a bit more boilerplate, but the code will not compile if you ask for the wrong type of animal and you can extend it easily without modifying the original Animal factory. This makes the code more modular and allows to isolate the possibly complex initialization of each type of animal.
Hi Mortimer, thank you for the valuable addition! It definitely might make sense for such a use case (even though it relies on static binding anyway). However, there might be no direct relation between the arguments and the concrete class, or the pattern can be used just to extract object creation code to a single method (or to cache created objects, etc.). I really tried hard to keep things simple for the sake of demonstration.
Joshua Bloch in Effective Java 2nd Edition:
Item 1: Consider static factory methods instead of constructors
The normal way for a class to allow a client to obtain an instance of itself is to provide a public constructor. There is another technique that should be a part of every programmer’s toolkit. A class can provide a public static factory method, which is simply a static method that returns an instance of the class. Here’s a simple example from Boolean (the boxed primitive class for the primitive type boolean). This method translates a boolean primitive value into a Boolean object reference:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
Note that a static factory method is not the same as the Factory Method pattern from Design Patterns [Gamma95, p. 107]. The static factory method described in this item has no direct equivalent in Design Patterns.
Joshua Kerievsky in Refactoring to Patterns:
Creation Methods and Factory Methods
What does our industry call a method that creates objects? Many programmers would answer “Factory Method,” after the name given to a creational pattern in Design Patterns [DP]. But are all methods that create objects true Factory Methods? Given a broad definition of the term (i.e., a method that simply creates objects), the answer would be an emphatic “yes!” But given the way the authors of the Factory Method pattern wrote it in 1995, it’s clear that not every method that creates objects offers the kind of loose coupling provided by a genuine Factory Method (e.g., see Introduce Polymorphic Creation with Factory Method, 88).
To help us be clear when discussing designs or refactorings related to object creation, I’m using the term Creation Method to refer to a static or nonstatic method that creates instances of a class. This means that every Factory Method is a Creation Method but not necessarily the reverse. It also means that you can substitute the term Creation Method wherever Martin Fowler uses the term “factory method” in ‘Refactoring’ and wherever Joshua Bloch uses the term “static factory method” in ‘Effective Java’.
In his ‘Refactoring’ book, Martin Fowler speaks of a Creation Method as a Factory Method: http://sourcemaking.com/refactoring/replace-constructor-with-factory-method
Martin Fowler in http://martinfowler.com/bliki/OOPSLA2004.html:
Before the beginning of the conference proper I attended a workshop on reappraising the GoF book, ten years after it came out. While the book is still essential reading for anyone in the OO space, there’s much that could be done to modernize it (although sadly it appears that probably won’t happen – at least by the GoF themselves).
We did a number of discussions around the what next theme, perhaps the most interesting one to report was an exercise in considering some to ‘vote off the island’. People voted on the patterns to indicate which ones they felt needed deletion in the current form.
Four patterns were voted off. Factory Method (due to the confusion over what it means – the pattern is different to the more common usage of the term)
Hi Philip! Thank you for the info. The GoF factory method pattern is indeed slightly different from the static factory method. To go along with the Wikipedia’s article I used the static factory method as an example for the factory method pattern, mentioning that it’s a “static” kind of factory in the comparison section. Now I’ve added a separate clarification to avoid the confusion.
Chain of responsibility by stackable trait is not good solution because stackable modificator applicable for traits but traits cann’t have constructor and this create some problems in chain definition.
post about chain of responsibility:
http://cogita-et-visa.blogspot.com/2012/12/chain-of-responsibility-in-scala.html?m=1
Hi Yuriy! Nice example per-se, yet it’s hardly a direct way of implementing the pattern relying on the language syntax, and it’s considerably more complex. Sure we can use all the Scala’s power to completely transcend all these patterns, but in this article I intentionally tried to avoid more advanced techniques in favor of more simple and pictorial ones, in order to provide a clean mapping between the two languages.
To be fair, Kent Beck, one of the pioneers of Design Patterns, is among those who defines the Factory Method design pattern differently from the GoF book. E.g. in ‘Test Driven Development: By Example’ he says of the pattern:
How do you create an object when you want flexibility in creating new objects? Create the object in a method instead of using a constructor.
Constructors are expressive. You can see that you are definitely creating an object when you use one. However, constructors, particularly in Java, lack expressiveness and flexibility.
…
One axis of flexibility that we wanted in our money example was to be able to return an object of a different class when we created an object.
…
By introducing a level of indirection, through a method, we gained the flexibility of returning an instance of a different class
…
public class Money{
…
static Dollar dollar(int amount) {
return new Dollar(amount);
}
…
}
This method is called a Factory Method, because it makes objects.
…
Use Factory Method only when you need the flexibility it creates. Otherwise, constructors work just fine for creating objects.
Kent Beck’s definition of Factory Method also appears in his later book, Implementation Patterns, which he says is not about design because it is mostly concerned with smaller-scale decisions, the kind programmers make many times a day:
“An alternative way to represent object creation is as a static method on the class. These methods have a couple of advantages over constructors: they can return a more abstract type (a subclass or an implementation of an interface) and they can be named after their intention, not just the class. However, factory methods add complexity, so they should be used when their advantages are valuable, not just as a matter of course.
…
If you intend something more complex than creating an object, like recording objects in a cache or creating a subclass that will be decided at runtime, then the factory method is helpful. However, as a reader I am always curious when I see a factory method. What else is going on there beyond object creation? I don’t want to waste my readers’ time, so if all that’s happening is vanilla object creation, I express it as a constructor. If something else is happening at the same time, I introduce a factory method to tip curious readers to this fact.”
@Pavel
>The GoF factory method pattern is indeed slightly different from the static factory method.
Yes, the definition is not this:
“The factory method pattern provides an interface for creating an object, but encapsulates the actual class instantiation in a method.’
The definition is this:
“The Factory Method Pattern defines an interface for creating an object, but lets SUBCLASSES decide which class to instantiate. Factory Method lets a class defer instantiation to SUBCLASSES.”
Philip, that’s true, the definition is also needs to be updated. I’ve amended the definition and moved the clarification before the examples. Thank you for the thoughtful comments!
Great article, Pavel. I’d say that the most ideomatic implementation of the chain of responsibility pattern in Scala is chaining of partial function with orElse:
def keyboardHandler: EventHandler = {
case Event(“keyboard”, _) => …
}
def mouseHandler: EventHandler = {
case Event(“mouse”, _) => …
}
def handler = keyboardHandler orElse mouseHandler
Roman, this is a nice idea. I’ll probably update the example. Thanks!
I have updated the example of the chain of responsibility pattern. On second thought, the approach is obvious and straightforward, I wonder how could I possibly overlook it initially. Once again, thanks to Roman!
Excellent writeup, now I’m even more enthusiastic about Scala!
Nice article 🙂
I’d also add that you can achieve a very slick decorator in functional style using currying and partial application. A simple example: https://gist.github.com/kciesielski/36d0e31b1d57772367e5
Your Java Singleton is wrong (see recent editions of Effective Java). The below is correct:
enum Cat implements Runnable {
INSTANCE;
public void run() {
// do nothing
}
}
Cat.INSTANCE.run();
Well not really, stateful singletons are an abomination. The only good singletons are constants and functionality without side-effects.
Very useful with simple examples that clearly show the intent of the patterns.
Thank you
Hi Scott! I’m aware of the implementation of Singleton pattern via enumerated types. It was tempting to use that code in the example, but it’s a trick nevertheless, so it’s not very appropriate for the demonstration. While it’s a good idea to use such an implementation in practice, enumerated types are not for singletons, after all. In Scala, objects are (usually) “good singletons” – they are used to hold pure functions and constants (somewhat similar to Haskell modules).
Thank you all for the valuable feedback! Your comments really helped me to shape and refine my talk for the JavaDay conference (slides of my presentation, the video is not available yet).
LinkedIn discussion that is relevant to the conversation.
Nice post! It’s nice to have something for Java people who are familiar with the GoF patterns to refer to when learning Scala. A couple minor things:
– Null Object: a key part of the Null Object pattern is that the null object implements the base interface (Sound in your Java example), so you can use the null object anywhere a Sound would be used. Option is a good complement to Null Object but not the same thing.
– Command: a by-name parameter is a parameter that is not evaluated at the call site, while Command is about encapsulating an action with its parameters, allowing it to stored and used after the fact. Think of Undo, one of the canonical Command use cases.
hi,
Good article but I don’t understand one part of the Command pattern.
Could you tell me what “command _ ” in the below code does? I don’t know what “_” represents here.
def invoke(command: => Unit) { // by-name parameter
command
history :+= command _ // WHAT _ means here,
}
It is used to convert “command” into a function of type () => Unit.
You can also use that technique to convert methods into functions. It is called “eta expansion”.
See http://gleichmann.wordpress.com/2011/01/09/functional-scala-turning-methods-into-functions/
Hi!
The “command _” expression (which looks like eta-expansion) is just a syntactic sugar for “() => command” function literal declaration, so that the “command” by-name parameter is not evaluated in-place, but rather wrapped in a Function0[Unit] instance.
By the way, such a syntax is (probably) not a part of the Scala language specification 🙂 Yet, we can always rewrite that expression as “() => command”.
Simply amazing, that’s why they said learning a new language helps to build your programming capability. By comparing their Java version with this, you can learn a lot more about language than reading nay book.
Thanks for the post, helped me a lot. One minor correction for you:
‘def use(a: Int, b: Int) { computer(a, b) }’ has to be => ‘def use(a: Int, b: Int) = { computer(a, b) }’
Won’t work without ‘=’
Hi Esfandiar! While it’s perfectly valid to use “=” in that definition, the original Java example declares Context.use method as “void” so the example in Scala just mirrors it (so that the method is called for its “side effect”, which is hardly advisable in real world code, yet it is beneficial in the example because it lowers the amount of returned values to consider).
Can implicit classes (when used to extend the functionality of a class) be considered an implementation of the decorator pattern as well?
Hi Noha!
I guess that, in such a case, comparison with the adapter pattern in more appropriate.
The decorator and adapter patterns are somehow similar, yet there’s basic difference in that decorator modifies behavior of particular class instances, preserving their original interface,
while adapter preserves behavior of class instances and modifies (or “extends”) their original interface.
We may rewrite val log: Log = new Logger() line from the adapter pattern example like (new Logger()).warning(“foo”), and both our intention and underlying mechanism will stay the same. The only difference is how long we may access the Logger instance via a single adapter wrapper.
So, interface extension via Scala implicit classes looks more like the adapter pattern (rather than the decorator pattern) implementation.
missing = on function in strategy pattern, this imply Unit for return value instead function result:
def use(a: Int, b: Int) { computer(a, b) }
it should be: def use(a: Int, b: Int) = computer(a, b)
Hi Marko!
Thanks for the remark. However that’s how it’s originally supposed to be, and the Java example mirrors the Scala code. The “Context.use” method implies presence of an algorithm that uses given strategy in some context.
I agree that, without an explicit algorithm definition, it looks like the strategy is called for some “unseen” side effect, and that’s rather confusing (yet, just returning the result of the call is also confusing, but in a different way).
I will probably add a comment about an implied algorithm there to clarify the intention.
Hey Pavel,
Ever since I saw that Peter Norvig said that “16 of 23 patterns are either invisible or simpler [with Dylan or Lisp]” (for those interested: http://norvig.com/design-patterns/design-patterns.pdf), I was curious to see the analogous with a powerful language that I love, Scala! So, thanks for this amazing post. Any chance we can see the rest of the patterns?
Thanks so much for this clear and well documented post.
My background is Smalltalk and I inhaled the GoF book when it originally came out.
I’m now coming up to speed on Scala and seeing the Scala version of the patterns is a very efficient and effective way for me to understand many of the important and powerful features of the language. (Learning the syntax is trivial; understanding the features is what’s important.)
I’ve seen a number of versions of the GoF patterns in Scala. Your post stands out because of you point out the important features. Thanks.
[…] Fatin有篇博客 Design Patterns in Scala […]
[…] Fatin在文章《 Design Patterns in Scala 》用OO设计模式中的Chain of […]
Great, this is amazing. Thank you.