Scala typeclass 设计模式

前言

本文的写作的灵感主要是看了这个视频 : Tutorial: Typeclasses in Scala with Dan Rosen

加上查阅了相关的资料,觉得可以写一篇博客,再加上也很久没写博客了。本文的主要内容

是根据参考资料对typeclass的解释再加上自己的一点点理解,代码会借(cao)鉴(xi)资料

中的例子(不过代码会稍作修改)。

正文

typeclass定义

首先简单看看维基上对于typeclass的定义:"In computer science, a type class is a type

system construct that supports ad hoc polymorphism." 这个“ad hoc polymorphism”

(特质多态)其实也被称作函数重载或运算符重载。

在scala中采用typeclass模式有什么有优点呢?总的来说就是:代码易扩展;代码写得好看。

在例子中理解 typeclass

以下用到的代码均借鉴自[2] 。

首先我们来看看两个 ADT 的定义:

就是定义了一个表达式ADT,还有Json ADT。

然后还有给表达式赋值的和输出Json的两个object :

简单测试一下:

然后现在想添加一个功能,就是给定某个类型的对象,获得该对象的json字符串。面向对象

的做法是声明一个JsonConvertible接口,然后让有需要类型去继承该接口,实现 convertToJson

方法。

现在想让Expression类型的对象都能转成Json类型,那么就是每个Expression类型都要去实现

converToJson方法。

然后我们可以简单测试一下:

然后现在问题来了,我们想保持Expression接口尽量的轻量,不想有太多的依赖,而且如果现在

又要增加一个新的trait那么Number、Multiply和Divide三个类又要去实现这个接口的方法。或者

如果Expression是属于第三方的库,无法修改来继承JsonConvertible怎么办?

这时候继承多态不适用了,我们要用特质多态来解决这个问题。

我们先来看看新的write函数定义,现在我们新加了一个helper类JsonConverter,这个类实现了

把value转化为Json类型的方法。然后我们来看看现在这么做的好处:

我们可以看到,现在Expression可以保持原来的样子,并且把Expression转化为Json的逻辑

与Expression的实现分开了。简单测试一下:

so far so good。但是现在想再进一步使实现更简洁一些,这个JsonConverter其实并不一定要

显式的传入,我们可以借助scala的implicit来实现。

就是在原来的基础上作些小修改,把expressionJsonConverter改为implicit,还有write函数

改为curry,conv参数改为implicit。简单测试一下:

更进一步我们可以用scala中的context bound来改写代码。

context bound 的表达形式是 A : B,意思是在上下文中存在隐式的 B[A] 类型的对象。

刚开始接触的时候我觉得context bound 和 view bound很像, A <% B,view bound的意思

你可以把A当作B来用,上下文中需要存在一个A到B的隐式转换。

ok,到此就是scala type class的简单介绍,视频中后面还有关于Expression和Json的重构并

扩展到 Int 和 Tuple 上,有兴趣的可以看看。

相关资料

[1] What are type classes in Scala useful for?

[2] Tutorial: Typeclasses in Scala with Dan Rosen

[3] The Neophyte's Guide to Scala Part 12: Type Classes

[4] Type class

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏iOS122-移动混合开发研究院

【读书笔记】A Swift Tour

素材:A Swift Tour 推荐下载Playground:Download Playground objc 自己较为熟悉,想熟悉下风头正劲的 swift。就...

3518
来自专栏Golang语言社区

在Go语言中使用JSON

Encode 将一个对象编码成JSON数据,接受一个interface{}对象,返回[]byte和error: func Marshal(v interfac...

3329
来自专栏数据结构与算法

病毒

【问题描述】   有一天,小y突然发现自己的计算机感染了一种病毒!还好,小y发现这种病毒很弱,只是会把文档中的所有字母替换成其它字母,但并不改变顺序,也不会增加...

4167
来自专栏老九学堂

十七个C语言新手编程时常犯的错误及解决方式

编译程序把a和A认为是两个不同的变量名,而显示出错信息。C认为大写字母和小写字母是两个不同的字符。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。

1324
来自专栏desperate633

LintCode 单词切分题目分析

给出一个字符串s和一个词典,判断字符串s是否可以被空格切分成一个或多个出现在字典中的单词。

692
来自专栏逸鹏说道

Python3 与 C# 基础语法对比(List、Tuple、Dict专栏)

Python3 与 C# 基础语法对比(基础知识场):https://www.cnblogs.com/dotnetcrazy/p/9102030.html

22510
来自专栏Ryan Miao

String.split()用法以及特殊分隔符注意,ps:|

转载:http://www.cnblogs.com/mingforyou/archive/2013/09/03/3299569.html 在java.lang包...

2869
来自专栏极乐技术社区

使用ES6新特性开发微信小程序(1)

ECMAScript 6(简称ES6)是JavaScript语言的最新标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。 ...

1945
来自专栏逸鹏说道

Python3 与 C# 基础语法对比(List、Tuple、Dict专栏)

Python3 与 C# 基础语法对比(基础知识场):https://www.cnblogs.com/dotnetcrazy/p/9102030.html

693
来自专栏PHP实战技术

PHP常用正则表达式大全

  匹配数字   "^\d+$" //非负整数(正整数 + 0)   "^[0-9]*[1-9][0-9]*$" //正整数   "^((-\d+)|(0+))...

3848

扫码关注云+社区