How Scala killed the Strategy Pattern

How Scala killed the Strategy Pattern

By Alvin Alexander. Last updated: Mar 23, 2014

table of contents [hide]

Summary: Simple functional programming techniques in Scala make certain OOP
design patterns, such as the Strategy Pattern, obsolete.

The OOP Strategy Pattern

Wikipedia describes the Strategy Pattern with this UML
diagram:

It’s further defined by the following Java code. But fear not, you don’t need
to read all the code, at least not yet; just note how long it
is as you scroll through it:

//___WIKIPEDIA CODE STARTS___

/** The classes that implement a concrete strategy should implement this. */

* The Context class uses this to call the concrete strategy. */
interface Strategy {
int execute(int a, int b);
};

/** Implements the algorithm using the strategy interface */
class Add implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Add‘s execute()");
return a + b; // Do an addition with a and b
}
};

class Subtract implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Subtract‘s execute()");
return a - b; // Do a subtraction with a and b
}
};

class Multiply implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Multiply‘s execute()");
return a * b; // Do a multiplication with a and b
}
};

// Configured with a ConcreteStrategy object and maintains
// a reference to a Strategy object
class Context {
private Strategy strategy;

public Context(Strategy strategy) {
this.strategy = strategy;
}

public int executeStrategy(int a, int b) {
return this.strategy.execute(a, b);
}
};

/** Tests the pattern */
class StrategyExample {
public static void main(String[] args) {
Context context;

// Three contexts following different strategies
context = new Context(new Add());
int resultA = context.executeStrategy(3,4);

context = new Context(new Subtract());
int resultB = context.executeStrategy(3,4);

context = new Context(new Multiply());
int resultC = context.executeStrategy(3,4);

System.out.println("Result A : " + resultA );
System.out.println("Result B : " + resultB );
System.out.println("Result C : " + resultC );
}
};

//___WIKIPEDIA CODE ENDS___


Two immediate thoughts


When I see code like this these days I think two things:

  1. Holy crap, that’s an insane amount of boilerplate code.

  2. I laugh, because I wrote Java code like that for what, almost 15 years?
    Shoot, I even taught UML classes.

I knew that code was insane, but perhaps because my background is in
aerospace engineering and not computer science, I didn’t know why.
Then I learned Scala.

How Scala killed the Strategy
Pattern

In contrast, Scala code tends to be much more concise. In this particular
case, because you can pass algorithms around just like you pass objects around,
there is no need for the Strategy Pattern, and you can write the code like this
instead:

object DeathToStrategy extends App {

def add(a: Int, b: Int) = a + b
def subtract(a: Int, b: Int) = a - b
def multiply(a: Int, b: Int) = a * b

def execute(callback:(Int, Int) => Int, x: Int, y: Int) = callback(x, y)

println("Add: " + execute(add, 3, 4))
println("Subtract: " + execute(subtract, 3, 4))
println("Multiply: " + execute(multiply, 3, 4))

}


That’s it, that’s all; 50+ lines of boilerplate code reduced to ~12, and it’s
still easy to read.

The only “secret sauce” to this recipe is knowing:

  • In Scala you can pass functions around just like other objects.

  • How to define the signature for a method
    like execute.

  • How to pass a function and variables into a method
    like execute.

If you’d like more information on how that code works, or on the difference
between a method and afunction in Scala, read
on; otherwise, move on and have a great day.

Understanding the ‘execute’
method

In this example I told the execute method that its
first parameter is a function that takes two Intparameters,
and returns an Int, like this:

callback:(Int, Int) => Int

The two Int parameters the function accepts are
enclosed in the parentheses, and the Int that is returned
by the function is shown on the right side of
the => symbol.

If you’re not used to functional programming in Scala, code like that may be
new, but as you can see, it’s pretty easy. It’s a little like a Java interface;
you’re defining the template for this method parameter, i.e., what this
parameter needs to look like when you call this method.

After defining that function as the first parameter of
the execute method, I declared that its second and third
parameters are Int values, like this:

x: Int, y: Int

That’s just the normal definition of Int parameters in
Scala. In Java that would look like this:

int x, int y

Finally, I told the execute method that when it’s
called it should run the callback function it was given
with the two parameters it was given:

callback(x, y)

Putting these snippets together leads to the code I showed earlier:

def execute(callback:(Int, Int) => Int, x: Int, y: Int) = callback(x, y)

Note that this is how I wrote my Scala code when I first started learning
Scala; the “callback” name helped reinforce what I was doing. These days I just
use the letter f instead
of callback:

def execute(f:(Int, Int) => Int, x: Int, y: Int) = f(x, y)

In my mind I now know that “f” means “function”, and I find this more
readable than using the name “callback”.

Dude, you used
‘method’ and ‘function’ interchangeably

In this article I used the terms “method” and “function” interchangeably,
because in most situations in Scala they are interchangeable.

As a quick example of this, you saw that I defined
the add method like this:

def add(a: Int, b: Int) = a + b

I can tell that this is a method because I defined it with
the def keyword. All methods begin with that keyword.

I could have defined it as a function if I wanted to. The
syntax for a function looks like this:

val add = (x: Int, y: Int) => x + y

After defining it as a function, I can use it just like I did earlier:

println("Add: " + execute(add, 3, 4))

How awesome is that?

In your own code you can define algorithms as methods or functions, however
you like. I find that methods are slightly easier to read, but functions are
cool because you define them as val, which reinforces the
notion that they are just values you can pass around, just like any other
object.

This is a beauty of Scala: You can use both. If you prefer one vs. the other,
awesome, use it.

What about those other OOP
design patterns?

Alas, Scala has killed not only the
Strategy design pattern
, but other design patterns as well. (I wrote this
series on Design Patterns
 six years ago.) I could write more, and maybe
one day I will, but if you start using Scala and the techniques shown in this
article, you’ll find this out very quickly for yourself.

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote
and released in late 2013:

You can find the Scala Cookbook at these locations:

I hope this tutorial has been helpful. All the best, Al.

tags:  

How Scala killed the Strategy Pattern,布布扣,bubuko.com

时间: 2024-10-04 09:30:09

How Scala killed the Strategy Pattern的相关文章

设计模式之Strategy Pattern

Declaration 首先声明, 本篇blog的内容是参考Design pattern FAQ Part 3 ( Design pattern training series)这篇博文写的, 图片也是来自这篇博客. 部分是翻译, 加上自己的理解形成这篇博文. 希望和大家一起学习设计模式, 共同进步. Scene for Strategy Pattern Strategy Pattern,这个翻译成策略模式应该是没有问题的.策略模式希望做到的是在运行的情况下,根据对象的类型选择使用的算法.简单来

设计模式之一:策略模式(Strategy Pattern)

在介绍策略模式之前先说下两个设计原则: 1.  Identify the aspects of your application that vary and separate them from what  stays the same.找到系统中变化的部分,将变化的部分同其它稳定的部分隔开. 2.  Program to an interface, not an implementation.面向接口编程,而不要面向实现编程. 那什么是策略模式呢? The Strategy Pattern d

策略模式(Strategy Pattern)

策略模式(Strategy Pattern) 抛开晦涩的定义,首先看一个例子: 我们想要创建一个模拟鸭子的游戏,在这个游戏中,会有各种类型的鸭子,比如mallard duck,red head duck,rubber duck(除了rubber duck(橡皮鸭),看见这其余两种鸭子很好奇,于是查找相关图片,发现mallard duck是绿头鸭,red head duck是红头鸭,自己生活中还没有见过,有趣,哈哈!三种鸭子图片如下所示). 回归话题,在这个模拟鸭子的游戏中,各种鸭子均有两种能力,

设计模式 - 策略模式(Strategy Pattern) 具体解释

策略模式(Strategy Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26577879 本文版权全部, 禁止转载, 如有须要, 请站内联系. 策略模式: 定义了算法族, 分别封装起来, 让它们之间能够相互替换, 此模式让算法的变化独立于使用算法的客户. 对于父类的子类族须要常常扩展新的功能, 为了使用父类比較灵活的加入子类, 把父类的行为写成接口(interface)的形式; 使用set()方法

Learning OpenCV Lecture 2 (Using the Strategy pattern in algorithm design)

ColorDetector.h: #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> class ColorDetector { public: // empty constructor ColorDetector() : minDist(100) { // default parameter initialization here target[0] = target[1] = targe

设计模式 - 策略模式(Strategy Pattern) 详解

策略模式(Strategy Pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26577879 本文版权所有, 禁止转载, 如有需要, 请站内联系. 策略模式: 定义了算法族, 分别封装起来, 让它们之间可以相互替换, 此模式让算法的变化独立于使用算法的客户. 对于父类的子类族需要经常扩展新的功能, 为了使用父类比较灵活的添加子类, 把父类的行为写成接口(interface)的形式; 使用set()方法,

Pattern Design - Strategy Pattern

If you can disassemble code  and  you want to apply one method of an object in another object that there is no inheritance between them, you can use Strategy Pattern. Aha, actually it is good strategy that we can wrap different kinds of algorithms, t

HF-DP1: strategy pattern

This is the 1st pattern I study. In here, I will mark down my doubts, java study, DESIGN PRINCIPLES, DESIGN PATTERN. There are 3 design principles in this pattern: 1. Identify the aspects of your application that vary and separate them from what stay

设计模式之策略模式(Strategy Pattern)

一.什么是策略模式(Strategy Pattern)? 从字面上理解,策略模式就是应用了某种“策略”的设计模式,而这个“策略”就是:把变化的部分封装起来. 二.举个例子 假定现在我们需要用类来描述Dog 首先,所有的Dog都有外形(比如Color),有行为(比如Run.Bark) 于是我们很自然地定义了这样一个基类Dog: public abstract class Dog { public abstract void display();//显示Dog的外形 public abstract