`
fujohnwang
  • 浏览: 156957 次
社区版块
存档分类
最新评论

ScalaPattern之Selfless Trait Pattern

阅读更多

原文出处:http://www.artima.com/scalazine/articles/selfless_trait_pattern.html

 

 

 

Summary
       This article describes a simple Scala design pattern that allows library designers to provide services that their clients can access either through mixins or imports. Giving users a choice between mixin composition and importing makes a library easier to use.

When designing a Scala library, you can partition the services offered by the library into traits. This gives your users more flexibility: they can mix into each class only the services they need from your library.

For example, in ScalaTest you create a basic suite of tests by mixing in any of several core Suite traits:

class MySuite extends Suite // a basic suite of test methods
class MySuite extends FunSuite // a basic suite of test functions
class MySpec extends Spec // a BDD-style suite of tests
class MyeSpec extends FeatureSpec // a higher level BDD-style suite 
class MySuite extends FixtureSuite // a suite of tests that take a fixture parameter

You can also mix in any of several other traits that add additional, or modify existing, behavior of the core trait:

class MySuite extends FunSuite with ShouldMatchers with EasyMockSugar with PrivateMethodTester

Although splitting a library's behavior into composable parts with traits gives users flexibility, one downside is that users may end up repeatedly mixing together the same traits, resulting in code duplication. User can easily eliminate this duplication, however, by creating a convenience trait that mixes together the behavior they prefer, and then mixing in that convenience trait into their classes instead. For example:

trait ProjectSpec extends WordSpec with ShouldMatchers with EasyMockSugar
class OneSpec extends ProjectSpec
class TwoSpec extends ProjectSpec
class RedSpec extends ProjectSpec with PrivateMethodTester
class BlueSpec extends ProjectSpec

Besides just mixing together the things they need, users can add value inside their convenience traits. For example, projects often require many tests that share a common fixture, such as a connection to a database containing a clean set of test data. This could be addressed simply by creating yet another trait that mixes in ProjectSpec and adds the needed pre- and post-test behavior:

trait DBProjectSpec extends ProjectSpec with BeforeAndAfterEach {
  override def beforeEach() {
    // initialize the database and open the connection
  }
  override def afterEach() {
    // clean up the database and close the connection
  }
}

Now test classes that need a database can simply mix in DBProjectSpec :

class MySpec extends DBProjectSpec

Although the ease of behavior composition afforded by traits is very useful, it has some downsides. One downside is that name conflicts are difficult to resolve. A user can't, for example, mix together two traits that contain methods with signatures that cause an overload conflict. Still another downside is that it is slightly awkward to experiment with the services offered by a trait in the Scala interpreter, because before the trait's services can be accessed, it must be mixed into some class or object. Both of these downsides can be addressed by making it easy to import the members of a trait as an alternative to mixing them in.

Implementing the selfless trait pattern

Scala has two features that make it easy to offer users this choice between mixins and imports. First, Scala allows users to import the members of any object. Second, Scala allows traits to have a companion object ---a singleton object that has the same name as its companion trait . You implement the selfless trait pattern simply by providing a companion object for a trait that itself mixes in the trait. Here's a simple example of the selfless trait pattern:

trait Friendly {
  def greet() { println("hi there") }
}

object Friendly extends Friendly

Trait Friendly in this example has one method, greet . It also has a companion object, named Friendly , which mixes in trait Friendly . Given this friendly design, client programmers of this library can access the services of Friendly either via mix in composition, like this (imports and uses of Friendly are in bold):

object MixinExample extends Application with Friendly
 {
  greet()

}

Or by importing the members of the Friendly companion object, like this:

import Friendly._


object ImportExample extends Application {
  greet()

}

Although the external behavior of MixinExample is the same as ImportExample , when MixinExample invokes greet it is calling greet on itself (i.e. , on this ), but when ImportExample invokes greet , it is calling greet on the Friendly singleton object. This is why being able to fall back on an import allows users resolve name conflicts. For example, a user would not be able to mix the following Functional trait into the same class as Friendly :

trait Functional {
  def greet: String = "hi there"
}

Because Friendly and Functional 's greet methods have the same signature but different return types, they will not overload if mixed into the same class:

object Problem extends Application with Friendly with Functional // Won't compile

By contrast, the offending method can be renamed on import, like this:

import Friendly.{greet => sayHi}


object Solved extends Application with Functional {
  sayHi()

  println(greet)
}

A good real-world example is trait ShouldMatchers from ScalaTest, which follows the selfless trait pattern. I expect the most common way ShouldMatchers will be used is by mixing it into test classes, often by means of a convenience trait. Here's an example:

import org.scalatest.WordSpec
import scala.collection.mutable.Stack
import org.scalatest.matchers.ShouldMatchers


class StackSpec extends WordSpec with ShouldMatchers
 {

  "A Stack" should {

    "pop values in last-in-first-out order" in {
      val stack = new Stack[Int]
      stack.push(1)
      stack.push(2)
      stack.pop() should be === 2
      stack.pop() should be === 1

    }

    "throw NoSuchElementException if an empty stack is popped" in {
      val emptyStack = new Stack[String]
      evaluating { emptyStack.pop() } should produce [NoSuchElementException]

    }
  }
}

Occasionally, however, users may want to experiment with the ShouldMatchers syntax in the Scala interpreter, which they can do with an import:

scala> import org.scalatest.matchers.ShouldMatchers._

import org.scalatest.matchers.ShouldMatchers._

scala> Map("hi" -> "there") should (contain key ("hi") and not contain value ("dude"))


scala> List(1, 2, 3) should have length 2

org.scalatest.TestFailedException: List(1, 2, 3) did not have length 2
	at org.scalatest.matchers.Matchers$class.newTestFailedException(Matchers.scala:148)
	at org.scalatest.matchers.ShouldMatchers$.newTestFailedException(ShouldMatchers.scala:2318)
	at org.scalatest.matchers.Matchers$ResultOfHaveWordForSeq.length(Matchers.scala:2891)
	at .(:7)
	at .()
	...

The reason this is called the selfless trait pattern is that it generally only makes sense to do this with traits that don't declare a self type. (A self type is a more specific type for this that restricts what the trait can be mixed into.) One other way in which traits that follow this pattern are "selfless" is that rather than forcing users to mix in their services they instead give users a choice: either mixing in the trait or importing the members of its companion object. If you are designing a Scala library that has a trait that doesn't declare a self type, consider implementing the Selfless Trait pattern by creating a companion object that mixes in the trait.

 

分享到:
评论

相关推荐

    Selfless-crx插件

    "Selfless-crx插件"是一款专为英语环境设计的浏览器扩展程序,其主要功能是自动将用户在浏览网页过程中遇到的"selfie"一词替换为"self portrait"。这款插件旨在提升网络阅读体验,帮助用户在文化语境中更加准确地...

    Selfless-Traffic-Routing-Testbed:基于SUMO的无私交通路由测试台

    基于SUMO(STR-SUMO)的无私流量路由测试平台 该项目基于SUMO( )构建,该平台提供了交通模拟平台。 STR-SUMO的目标是提供一个测试平台,可以在以下约束条件下对路由策略的性能进行基准测试: ...

    无私「Selfless」-crx插件

    将“Selfie”一词替换为“Self Portrait” 扫描网页中是否出现“ selfie”一词,并将其替换为“ self portrait”。 支持语言:English

    高考英语写作之四如何达到词汇高级化.doc

    例如,将"good"替换为"kind, honest, generous, selfless, brave, warm-hearted, sympathetic, honorable, humorous, smart, gentle"等人格特质词,或者在描述事物时用"great, fantastic, splendid, marvelous, ...

    感谢母亲的信,英语精选.doc

    同时,信件中出现的词汇如"concern"、"sacrifice"和"selfless"等,不仅展示了作者的英语词汇水平,也深化了情感表达的内涵。 庆祝母亲节的习俗在信中得到了体现。这是一个全球性的节日,人们通过各种方式来表达对...

    高考英语书面表达感谢信必备开头结尾知识.docx

    I am most grateful for your selfless donation. 4. 我代表我的全家再次向你所做的一切表达感谢。祝你万事如意!I, (on behalf of) my whole family/class/school, would like to thank you again for what you ...

    感谢父母的英语作文15篇.docx

    学习这些作文,学生可以了解到如何用英语描述情感,如使用诸如"tenderness"、"selfless"等词来描绘母爱的特质;如何构建有深度的比喻,比如"like a beautiful angel"和"a blue sky";以及如何用恰当的句式表达感激,...

    感谢信英文.doc

    - 结束时,可以使用"I must thank you again for your generous help."或"I am most grateful for your selfless donation."这样的句子,以再次确认你的感激之情。 以上是关于如何撰写英语感谢信的全面解析,包括...

    基于B/S结构的通信原理仿真平台的源代码和技术报告

    这是一个基于B/S结构的通信原理仿真平台的源代码和技术报告还有Demo。它可以帮助你建立一个通信原理网上实验室,为学生提供在线实验。...her selfless help, I couldn’t finish the program in time

    初三英语中考模拟试题及答案.doc

    题目:—It is selfless the most beautiful teacher—Yang Xiangming to lose his life the child in the river. 答案:B. of; to save 解析:"It is + 形容词 + of sb. to do sth."结构强调的是某人的品质,这里...

    普通高中课程标准英语必修一unitreading修改PPT学习教案.pptx

    - 掌握形容词如selfless(无私的)、determined(坚定的)、generous(慷慨的)等描述伟人品质的词语。 2. **语法与句型**: - 使用了not only...but also...结构来描述人物品质,如"He is not only kind-hearted...

    Parent单复数用法.doc

    - **与either**:指两者之一,例如:"Either parent can attend the school meeting."(父母任何一方都可以参加学校会议。) - **与all**:通常不直接与"parent"的复数形式搭配,因为"all"表示三个或更多,但可以...

    浙江省诸暨市牌头中学2016届高三英语复习Unit5NelsonMandela练习新人教版必修1

    1. **词汇填空**:这部分考察了对Nelson Mandela个人特质的形容,如无私(selfless)、随和(easy-going)、慷慨(generous)以及他对帮助贫穷黑人学习的承诺(devoted)。他还作为一名律师(lawyer),为贫困的黑人...

    初三英语中考模拟考试题和答案OK.doc

    在初中阶段,英语是中考的重要科目之一,而模拟考试是学生们备考的关键环节。这份“初三英语中考模拟考试题和答案OK.doc”文件显然是为帮助学生熟悉考试格式、提升英语水平而设计的。下面我们将对其中的部分题目进行...

    2021版新高考英语一轮复习Module4ASocialSurvey_MyNeighbourhood课后达标检测外研版必修1

    5. 英语词汇学习:如"homeless"(无家可归的),"extreme weather"(极端天气),"shelter"(避难所),"selfless act"(无私的行为)等,这些都是与社会问题和人道主义相关的词汇。 6. 预备高考:这部分内容可能是...

    最新 读后续写范文复习巩固专讲专练(章末复习+综合测评+答案).doc

    The guilt of his deceit weighed heavily upon him, and the image of Nabor's selfless act began to erode his cunning facade. Nabor continued, "My horse is more than just an animal; it represents trust ...

    高中英语感谢信PPT学习教案.pptx

    【知识点详解】 在高中英语学习中,撰写感谢信是一项重要的写作技能。感谢信不仅能够体现个人的礼貌与修养,还能有效提升沟通...在实际应用中,这些技巧将帮助他们更好地表达对他人的感激之情,展现良好的社交礼仪。

    初三英语中考模拟试题及答案-中考模拟试题英语答案.doc

    7. 形容词selfless(无私的)表明品质,用of连接主语,不定式to save表目的,答案为B. of; to save。 8. 句子中表示搭建帐篷过夜,使用put up,答案为B. put up。 9. 回答用一般现在时态表示将来,因此选A. is ...

    考研飞跃计划英语词根词缀思维导图笔记(%202021考研.zip

    4. **常用词缀组合**:列举一些常见词缀组合,如“self-”与“-less”构成“selfless”(无私的),让考生理解词缀的组合规律。 5. **记忆策略**:提供词根词缀的记忆方法,如联想记忆、分类记忆等,帮助考生提高...

    2020版高考英语总复习 Unit 5 Nelson Mandela—a modern hero练习 1.doc

    5. 此处需要两个形容词修饰“manner”,“selfless”意为无私的,“devoted”意为忠诚的。 6. "escape doing sth." 表示逃避做某事,故填“being fired”。 7. "be equal to doing sth." 是固定搭配,意为胜任做某...

Global site tag (gtag.js) - Google Analytics