Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

which GOF Design pattern(s) has entirely different implementation (java vs Scala)

Recently I read following SO question :

Is there any use cases for employing the Visitor Pattern in Scala? Should I use Pattern Matching in Scala every time I would have used the Visitor Pattern in Java?

The link to the question with title: Visitor Pattern in Scala. The accepted answer begins with

Yes, you should probably start off with pattern matching instead of the visitor pattern. See this http://www.artima.com/scalazine/articles/pattern_matching.html

My question (inspired by above mentioned question) is which GOF Design pattern(s) has entirely different implementation in Scala? Where should I be careful and not follow java based programming model of Design Patterns (Gang of Four), if I am programming in Scala?

Creational patterns

  • Abstract Factory
  • Builder
  • Factory Method
  • Prototype
  • Singleton : Directly create an Object (scala)

Structural patterns

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Proxy

Behavioral patterns

  • Chain of responsibility
  • Command
  • Interpreter
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Template method
  • Visitor : Patten Matching (scala)
like image 807
Optimight Avatar asked Jun 20 '12 16:06

Optimight


People also ask

What is GoF Design Patterns in Java?

The GoF Design Patterns are broken into three categories: Creational Patterns for the creation of objects; Structural Patterns to provide relationship between objects; and finally, Behavioral Patterns to help define how objects interact.

What is design pattern in Scala?

Design patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system. The classical design patterns are the 23 design patterns by GoF. This project implements dozens of design patterns in Scala.

Which design pattern is mostly used in Java?

Factory Pattern We can apply a Singleton pattern on the Factory class or make the factory method static. Check out Factory Design Pattern for example program and factory pattern benefits. This is one of the most widely used java design patterns.

Are design patterns same in all languages?

Yes and no. Certain design patterns are not specific to particular languages, but there may be design patterns specific to classes of languages. For example, there may be functional design patterns that are specific to functional languages or object oriented design patterns specific to object oriented languages.


2 Answers

For almost all of these, there are Scala alternatives that cover some but not all of the use cases for these patterns. All of this is IMO, of course, but:

Creational Patterns

Builder

Scala can do this more elegantly with generic types than can Java, but the general idea is the same. In Scala, the pattern is most simply implemented as follows:

trait Status trait Done extends Status trait Need extends Status  case class Built(a: Int, b: String) {} class Builder[A <: Status, B <: Status] private () {   private var built = Built(0,"")   def setA(a0: Int) = { built = built.copy(a = a0); this.asInstanceOf[Builder[Done,B]] }   def setB(b0: String) = { built = built.copy(b = b0); this.asInstanceOf[Builder[A,Done]] }   def result(implicit ev: Builder[A,B] <:< Builder[Done,Done]) = built } object Builder {   def apply() = new Builder[Need, Need] } 

(If you try this in the REPL, make sure that the class and object Builder are defined in the same block, i.e. use :paste.) The combination of checking types with <:<, generic type arguments, and the copy method of case classes make a very powerful combination.

Factory Method (and Abstract Factory Method)

Factory methods' main use is to keep your types straight; otherwise you may as well use constructors. With Scala's powerful type system, you don't need help keeping your types straight, so you may as well use the constructor or an apply method in the companion object to your class and create things that way. In the companion-object case in particular, it is no harder to keep that interface consistent than it is to keep the interface in the factory object consistent. Thus, most of the motivation for factory objects is gone.

Similarly, many cases of abstract factory methods can be replaced by having a companion object inherit from an appropriate trait.

Prototype

Of course overridden methods and the like have their place in Scala. However, the examples used for the Prototype pattern on the Design Patterns web site are rather inadvisable in Scala (or Java IMO). However, if you wish to have a superclass select actions based on its subclasses rather than letting them decide for themselves, you should use match rather than the clunky instanceof tests.

Singleton

Scala embraces these with object. They are singletons--use and enjoy!

Structural Patterns

Adapter

Scala's trait provides much more power here--rather than creating a class that implements an interface, for example, you can create a trait which implements only part of the interface, leaving the rest for you to define. For example, java.awt.event.MouseMotionListener requires you to fill in two methods:

def mouseDragged(me: java.awt.event.MouseEvent) def mouseMoved(me: java.awt.event.MouseEvent) 

Maybe you want to ignore dragging. Then you write a trait:

trait MouseMoveListener extends java.awt.event.MouseMotionListener {   def mouseDragged(me: java.awt.event.MouseEvent) {} } 

Now you can implement only mouseMoved when you inherit from this. So: similar pattern, but much more power with Scala.

Bridge

You can write bridges in Scala. It's a huge amount of boilerplate, though not quite as bad as in Java. I wouldn't recommend routinely using this as a method of abstraction; think about your interfaces carefully first. Keep in mind that with the increased power of traits that you can often use those to simplify a more elaborate interface in a place where otherwise you might be tempted to write a bridge.

In some cases, you may wish to write an interface transformer instead of the Java bridge pattern. For example, perhaps you want to treat drags and moves of the mouse using the same interface with only a boolean flag distinguishing them. Then you can

trait MouseMotioner extends java.awt.event.MouseMotionListener {   def mouseMotion(me: java.awt.event.MouseEvent, drag: Boolean): Unit   def mouseMoved(me: java.awt.event.MouseEvent) { mouseMotion(me, false) }   def mouseDragged(me: java.awt.event.MouseEvent) { mouseMotion(me, true) } } 

This lets you skip the majority of the bridge pattern boilerplate while accomplishing a high degree of implementation independence and still letting your classes obey the original interface (so you don't have to keep wrapping and unwrapping them).

Composite

The composite pattern is particularly easy to achieve with case classes, though making updates is rather arduous. It is equally valuable in Scala and Java.

Decorator

Decorators are awkward. You usually don't want to use the same methods on a different class in the case where inheritance isn't exactly what you want; what you really want is a different method on the same class which does what you want instead of the default thing. The enrich-my-library pattern is often a superior substitute.

Facade

Facade works better in Scala than in Java because you can have traits carry partial implementations around so you don't have to do all the work yourself when you combine them.

Flyweight

Although the flyweight idea is as valid in Scala as Java, you have a couple more tools at your disposal to implement it: lazy val, where a variable is not created unless it's actually needed (and thereafter is reused), and by-name parameters, where you only do the work required to create a function argument if the function actually uses that value. That said, in some cases the Java pattern stands unchanged.

Proxy

Works the same way in Scala as Java.

Behavioral Patterns

Chain of responsibility

In those cases where you can list the responsible parties in order, you can

xs.find(_.handleMessage(m)) 

assuming that everyone has a handleMessage method that returns true if the message was handled. If you want to mutate the message as it goes, use a fold instead.

Since it's easy to drop responsible parties into a Buffer of some sort, the elaborate framework used in Java solutions rarely has a place in Scala.

Command

This pattern is almost entirely superseded by functions. For example, instead of all of

public interface ChangeListener extends EventListener {   void stateChanged(ChangeEvent e) } ... void addChangeListener(ChangeListener listener) { ... } 

you simply

def onChange(f: ChangeEvent => Unit) 

Interpreter

Scala provides parser combinators which are dramatically more powerful than the simple interpreter suggested as a Design Pattern.

Iterator

Scala has Iterator built into its standard library. It is almost trivial to make your own class extend Iterator or Iterable; the latter is usually better since it makes reuse trivial. Definitely a good idea, but so straightforward I'd hardly call it a pattern.

Mediator

This works fine in Scala, but is generally useful for mutable data, and even mediators can fall afoul of race conditions and such if not used carefully. Instead, try when possible to have your related data all stored in one immutable collection, case class, or whatever, and when making an update that requires coordinated changes, change all things at the same time. This won't help you interface with javax.swing, but is otherwise widely applicable:

case class Entry(s: String, d: Double, notes: Option[String]) {}  def parse(s0: String, old: Entry) = {   try { old.copy(s = s0, d = s0.toDouble) }   catch { case e: Exception => old } } 

Save the mediator pattern for when you need to handle multiple different relationships (one mediator for each), or when you have mutable data.

Memento

lazy val is nearly ideal for many of the simplest applications of the memento pattern, e.g.

class OneRandom {   lazy val value = scala.util.Random.nextInt } val r = new OneRandom r.value  // Evaluated here r.value  // Same value returned again 

You may wish to create a small class specifically for lazy evaluation:

class Lazily[A](a: => A) {   lazy val value = a } val r = Lazily(scala.util.Random.nextInt) // not actually called until/unless we ask for r.value 

Observer

This is a fragile pattern at best. Favor, whenever possible, either keeping immutable state (see Mediator), or using actors where one actor sends messages to all others regarding the state change, but where each actor can cope with being out of date.

State

This is equally useful in Scala, and is actually the favored way to create enumerations when applied to methodless traits:

sealed trait DayOfWeek final trait Sunday extends DayOfWeek ... final trait Saturday extends DayOfWeek 

(often you'd want the weekdays to do something to justify this amount of boilerplate).

Strategy

This is almost entirely replaced by having methods take functions that implement a strategy, and providing functions to choose from.

def printElapsedTime(t: Long, rounding: Double => Long = math.round) {   println(rounding(t*0.001)) } printElapsedTime(1700, math.floor)  // Change strategy 

Template Method

Traits offer so many more possibilities here that it's best to just consider them another pattern. You can fill in as much code as you can from as much information as you have at your level of abstraction. I wouldn't really want to call it the same thing.

Visitor

Between structural typing and implicit conversion, Scala has astoundingly more capability than Java's typical visitor pattern. There's no point using the original pattern; you'll just get distracted from the right way to do it. Many of the examples are really just wishing there was a function defined on the thing being visited, which Scala can do for you trivially (i.e. convert an arbitrary method to a function).

like image 149
Rex Kerr Avatar answered Oct 28 '22 23:10

Rex Kerr


Ok, let's have a brief look at these patterns. I'm looking at all these patterns purely from a functional programming point of view, and leaving out many things that Scala can improve from an OO point of view. Rex Kerr answer provides an interesting counter-point to my own answers (I only read his answer after writing my own).

With that in mind, I'd like to say that it is important to study persistent data structures (functionally pure data structures) and monads. If you want to go deep, I think category theory basics are important -- category theory can formally describe all program structures, including imperative ones.

Creational Patterns

A constructor is nothing more than a function. A parameterless constructor for type T is nothing more than a function () => T, for example. In fact, Scala's syntactical sugar for functions is taken advantage on case classes:

case class T(x: Int) 

That is equivalent to:

class T(val x: Int) { /* bunch of methods */ } object T {   def apply(x: Int) = new T(x)   /* other stuff */ } 

So that you can instantiate T with T(n) instead of new T(n). You could even write it like this:

object T extends Int => T {   def apply(x: Int) = new T(x)   /* other stuff */ } 

Which turns T into a formal function, without changing any code.

This is the important point to keep in mind when thinking of creational patterns. So let's look at them:

Abstract Factory

This one is unlikely to change much. A class can be thought of as a group of closely related functions, so a group of closely related functions is easily implemented through a class, which is what this pattern does for constructors.

Builder

Builder patterns can be replaced by curried functions or partial function applications.

def makeCar: Size => Engine => Luxuries => Car = ??? def makeLargeCars = makeCar(Size.Large) _  def makeCar: (Size, Engine, Luxuries) => Car = ??? def makeLargeCars = makeCar(Size.Large, _: Engine, _: Luxuries) 

Factory Method

Becomes obsolete if you discard subclassing.

Prototype

Doesn't change -- in fact, this is a common way of creating data in functional data structures. See case classes copy method, or all non-mutable methods on collections which return collections.

Singleton

Singletons are not particularly useful when your data is immutable, but Scala object implements this pattern is a safe manner.

Structural Patterns

This is mostly related to data structures, and the important point on functional programming is that the data structures are usually immutable. You'd be better off looking at persistent data structures, monads and related concepts than trying to translate these patterns.

Not that some patterns here are not relevant. I'm just saying that, as a general rule, you should look into the things above instead of trying to translate structural patterns into functional equivalents.

Adapter

This pattern is related to classes (nominal typing), so it remains important as long as you have that, and is irrelevant when you don't.

Bridge

Related to OO architecture, so the same as above.

Composite

Lot at Lenses and Zippers.

Decorator

A Decorator is just function composition. If you are decorating a whole class, that may not apply. But if you provide your functionality as functions, then composing a function while maintaining its type is a decorator.

Facade

Same comment as for Bridge.

Flyweight

If you think of constructors as functions, think of flyweight as function memoization. Also, Flyweight is intrinsic related to how persistent data structures are built, and benefits a lot from immutability.

Proxy

Same comment as for Adapter.

Behavioral Patterns

This is all over the place. Some of them are completely useless, while others are as relevant as always in a functional setting.

Chain of Responsibility

Like Decorator, this is function composition.

Command

This is a function. The undo part is not necessary if your data is immutable. Otherwise, just keep a pair of function and its reverse. See also Lenses.

Interpreter

This is a monad.

Iterator

It can be rendered obsolete by just passing a function to the collection. That's what Traversable does with foreach, in fact. Also, see Iteratee.

Mediator

Still relevant.

Memento

Useless with immutable objects. Also, its point is keeping encapsulation, which is not a major concern in FP.

Note that this pattern is not serialization, which is still relevant.

Observer

Relevant, but see Functional Reactive Programming.

State

This is a monad.

Strategy

A strategy is a function.

Template Method

This is an OO design pattern, so it's relevant for OO designs.

Visitor

A visitor is just a method receiving a function. In fact, that's what Traversable's foreach does.

In Scala, it can also be replaced with extractors.

like image 24
Daniel C. Sobral Avatar answered Oct 29 '22 00:10

Daniel C. Sobral