@@ -32,17 +32,41 @@ It’s more about modeling operations, imho.”
3232How to resolve? Is there a good DDD term to use here?
3333{% endcomment %}
3434
35- ### traits
35+ ### Traits
3636
3737Scala trait 可以用作简单的接口,但它们也可以包含抽象和具体的方法和字段,并且它们可以有参数,就像类一样。
3838它们为您提供了一种将行为组织成小型模块化单元的好方法。
3939稍后,当您想要创建属性和行为的具体实现时,类和对象可以扩展特征,根据需要混合尽可能多的特征以实现所需的行为。
4040
4141作为如何将 traits 用作接口的示例,以下是三个 traits,它们为狗和猫等动物定义了结构良好并且模块化的行为:
4242
43+ {% tabs traits class=tabs-scala-version %}
44+ {% tab 'Scala 2' for=traits %}
45+
46+ ``` scala
47+ trait Speaker {
48+ def speak (): String // has no body, so it’s abstract
49+ }
50+
51+ trait TailWagger {
52+ def startTail (): Unit = println(" tail is wagging" )
53+ def stopTail (): Unit = println(" tail is stopped" )
54+ }
55+
56+ trait Runner {
57+ def startRunning (): Unit = println(" I’m running" )
58+ def stopRunning (): Unit = println(" Stopped running" )
59+ }
60+ ```
61+
62+ {% endtab %}
63+
64+ {% tab 'Scala 3' for=traits %}
65+
66+
4367``` scala
4468trait Speaker :
45- def speak (): String // 没有函数体,这样它是抽象的。
69+ def speak (): String // has no body, so it’s abstract
4670
4771trait TailWagger :
4872 def startTail (): Unit = println(" tail is wagging" )
@@ -53,26 +77,80 @@ trait Runner:
5377 def stopRunning (): Unit = println(" Stopped running" )
5478```
5579
80+ {% endtab %}
81+ {% endtabs %}
82+
5683鉴于这些特征,这里有一个 ` Dog ` 类,它扩展了所有这些特征,同时为抽象 ` speak ` 方法提供了一种行为:
5784
85+ {% tabs traits-class class=tabs-scala-version %}
86+ {% tab 'Scala 2' for=traits-class %}
87+
88+ ``` scala
89+ class Dog (name : String ) extends Speaker with TailWagger with Runner {
90+ def speak (): String = " Woof!"
91+ }
92+ ```
93+
94+ {% endtab %}
95+
96+ {% tab 'Scala 3' for=traits-class %}
97+
5898``` scala
5999class Dog (name : String ) extends Speaker , TailWagger , Runner :
60100 def speak (): String = " Woof!"
61101```
62102
103+ {% endtab %}
104+ {% endtabs %}
105+
63106请注意该类如何使用 ` extends ` 关键字扩展 traits。
64107
65108类似地,这里有一个 ` Cat ` 类,它实现了这些相同的 traits,同时还覆盖了它继承的两个具体方法:
66109
110+ {% tabs traits-override class=tabs-scala-version %}
111+ {% tab 'Scala 2' for=traits-override %}
112+
113+ ``` scala
114+ class Cat (name : String ) extends Speaker with TailWagger with Runner {
115+ def speak (): String = " Meow"
116+ override def startRunning (): Unit = println(" Yeah ... I don’t run" )
117+ override def stopRunning (): Unit = println(" No need to stop" )
118+ }
119+ ```
120+
121+ {% endtab %}
122+
123+ {% tab 'Scala 3' for=traits-override %}
124+
67125``` scala
68126class Cat (name : String ) extends Speaker , TailWagger , Runner :
69127 def speak (): String = " Meow"
70128 override def startRunning (): Unit = println(" Yeah ... I don’t run" )
71129 override def stopRunning (): Unit = println(" No need to stop" )
72130```
73131
132+ {% endtab %}
133+ {% endtabs %}
134+
74135这些示例显示了如何使用这些类:
75136
137+ {% tabs traits-use class=tabs-scala-version %}
138+ {% tab 'Scala 2' for=traits-use %}
139+
140+ ``` scala
141+ val d = new Dog (" Rover" )
142+ println(d.speak()) // prints "Woof!"
143+
144+ val c = new Cat (" Morris" )
145+ println(c.speak()) // "Meow"
146+ c.startRunning() // "Yeah ... I don’t run"
147+ c.stopRunning() // "No need to stop"
148+ ```
149+
150+ {% endtab %}
151+
152+ {% tab 'Scala 3' for=traits-use %}
153+
76154``` scala
77155val d = Dog (" Rover" )
78156println(d.speak()) // prints "Woof!"
@@ -83,6 +161,9 @@ c.startRunning() // "Yeah ... I don’t run"
83161c.stopRunning() // "No need to stop"
84162```
85163
164+ {% endtab %}
165+ {% endtabs %}
166+
86167如果该代码有意义---太好了,您把 traits 作为接口感到舒服。
87168如果没有,请不要担心,它们在 [ Domain Modeling] [ data-1 ] 章节中有更详细的解释。
88169
@@ -91,6 +172,24 @@ c.stopRunning() // "No need to stop"
91172Scala _ classes_ 用于 OOP 风格的编程。
92173这是一个模拟“人”的类的示例。在 OOP 中,字段通常是可变的,所以 ` firstName ` 和 ` lastName ` 都被声明为 ` var ` 参数:
93174
175+ {% tabs class_1 class=tabs-scala-version %}
176+ {% tab 'Scala 2' for=class_1 %}
177+
178+ ``` scala
179+ class Person (var firstName : String , var lastName : String ) {
180+ def printFullName () = println(s " $firstName $lastName" )
181+ }
182+
183+ val p = new Person (" John" , " Stephens" )
184+ println(p.firstName) // "John"
185+ p.lastName = " Legend"
186+ p.printFullName() // "John Legend"
187+ ```
188+
189+ {% endtab %}
190+
191+ {% tab 'Scala 3' for=class_1 %}
192+
94193``` scala
95194class Person (var firstName : String , var lastName : String ):
96195 def printFullName () = println(s " $firstName $lastName" )
@@ -101,13 +200,31 @@ p.lastName = "Legend"
101200p.printFullName() // "John Legend"
102201```
103202
203+ {% endtab %}
204+ {% endtabs %}
205+
104206请注意,类声明创建了一个构造函数:
105207
106- ``` 斯卡拉
208+ {% tabs class_2 class=tabs-scala-version %}
209+ {% tab 'Scala 2' for=class_2 %}
210+
211+ ``` scala
212+ // this code uses that constructor
213+ val p = new Person (" John" , " Stephens" )
214+ ```
215+
216+ {% endtab %}
217+
218+ {% tab 'Scala 3' for=class_2 %}
219+
220+ ``` scala
107221// 此代码使用该构造函数
108222val p = Person (" 约翰" , " 斯蒂芬斯" )
109223```
110224
225+ {% endtab %}
226+ {% endtabs %}
227+
111228[ Domain Modeling] [ data-1 ] 章节中介绍了构造函数和其他与类相关的主题。
112229
113230## FP 领域建模
@@ -120,20 +237,57 @@ to replace the Scala2 “sealed trait + case class” pattern. How to resolve?
120237
121238以 FP 风格编写代码时,您将使用以下结构:
122239
123- - 枚举来定义 ADT
124- - 样例类
125- - Traits
240+ - 代数数据类型(ADT)来定义数据
241+ - Traits 来定义数据上的功能
242+
243+ ### 枚举和 Sum Types
126244
127- ### 枚举
245+ Sum types 是在 Scala 中给代数数据类型(ADT)建模的一种方法。
128246
129247` enum ` 构造是在 Scala 3 中对代数数据类型 (ADT) 进行建模的好方法。
248+
130249例如,披萨具有三个主要属性:
131250
132251- 面饼大小
133252- 面饼类型
134253- 馅料
135254
136- 这些是用枚举简洁地建模的:
255+ 这些是用枚举简洁地建模的,它们是只包含单例值的 sum types:
256+
257+ {% tabs enum_1 class=tabs-scala-version %}
258+ {% tab 'Scala 2' for=enum_1 %}
259+
260+ 在 Scala 2 中,用 ` sealed ` 类和 ` case object ` 组合在一起来定义枚举:
261+
262+ ``` scala
263+ sealed abstract class CrustSize
264+ object CrustSize {
265+ case object Small extends CrustSize
266+ case object Medium extends CrustSize
267+ case object Large extends CrustSize
268+ }
269+
270+ sealed abstract class CrustType
271+ object CrustType {
272+ case object Thin extends CrustType
273+ case object Thick extends CrustType
274+ case object Regular extends CrustType
275+ }
276+
277+ sealed abstract class Topping
278+ object Topping {
279+ case object Cheese extends Topping
280+ case object Pepperoni extends Topping
281+ case object BlackOlives extends Topping
282+ case object GreenOlives extends Topping
283+ case object Onions extends Topping
284+ }
285+ ```
286+
287+ {% endtab %}
288+ {% tab 'Scala 3' for=enum_1 %}
289+
290+ Scala 3 提供了 ` enum ` 结构来定义枚举:
137291
138292``` scala
139293enum CrustSize :
@@ -146,8 +300,32 @@ enum Topping:
146300 case Cheese , Pepperoni , BlackOlives , GreenOlives , Onions
147301```
148302
303+ {% endtab %}
304+ {% endtabs %}
305+
149306一旦你有了一个枚举,你就可以按照你通常使用特征、类或对象的所有方式来使用枚举:
150307
308+ {% tabs enum_2 class=tabs-scala-version %}
309+ {% tab 'Scala 2' for=enum_2 %}
310+
311+ ``` scala
312+ import CrustSize ._
313+ val currentCrustSize = Small
314+
315+ // enums in a `match` expression
316+ currentCrustSize match {
317+ case Small => println(" Small crust size" )
318+ case Medium => println(" Medium crust size" )
319+ case Large => println(" Large crust size" )
320+ }
321+
322+ // enums in an `if` statement
323+ if (currentCrustSize == Small ) println(" Small crust size" )
324+ ```
325+
326+ {% endtab %}
327+ {% tab 'Scala 3' for=enum_2 %}
328+
151329``` scala
152330import CrustSize .*
153331val currentCrustSize = Small
@@ -162,19 +340,42 @@ currentCrustSize match
162340if currentCrustSize == Small then println(" Small crust size" )
163341```
164342
165- 下面是另一个如何在 Scala 中创建和使用 ADT 的示例:
343+ {% endtab %}
344+ {% endtabs %}
345+
346+ 下面是另一个如何在 Scala 中创建 sum type 的示例,它不能被叫作枚举,因为 ` succ ` 样例类有参数:的示例:
347+
348+ {% tabs enum_3 class=tabs-scala-version %}
349+ {% tab 'Scala 2' for=enum_3 %}
350+
351+ ``` scala
352+ sealed abstract class Nat
353+ object Nat {
354+ case object Zero extends Nat
355+ case class Succ (pred : Nat ) extends Nat
356+ }
357+ ```
358+
359+ Sum Types 在本书的[ 领域建模] ({% link _ overviews/scala3-book/domain-modeling-tools.md %})部分有详细的介绍。
360+
361+ {% endtab %}
362+ {% tab 'Scala 3' for=enum_3 %}
166363
167364``` scala
168365enum Nat :
169366 case Zero
170367 case Succ (pred : Nat )
171368```
172369
173- 枚举在本书的 [ 领域建模] [ data-1 ] 部分和 [ 参考文档] ({{ site.scala3ref }}/enums/enums.html) 中有详细介绍。
370+ 枚举在本书的 [ 领域建模] ({% link _ overviews/scala3-book/domain-modeling-tools.md %})部分和 [ 参考文档] ({{ site.scala3ref }}/enums/enums.html) 中有详细介绍。
371+
372+ {% endtab %}
373+ {% endtabs %}
174374
175- ### 样例类
375+ ### Product Types
376+
377+ product type 是代数数据类型(ADT),它只含有一个形状,例如一个单例对象,在Scala 中用 ` case ` 对象来代表;或者是一个可以获取字段的不可变结构,用 ` case ` 类来代表。
176378
177- Scala ` case ` 类允许您使用不可变数据结构对概念进行建模。
178379` case ` 类具有 ` class ` 的所有功能,还包含其他功能,使它们对函数式编程很有用。
179380当编译器在 ` class ` 前面看到 ` case ` 关键字时,它具有以下效果和好处:
180381
@@ -193,6 +394,9 @@ NOTE: Julien had a comment about how he decides when to use case classes vs clas
193394
194395这段代码演示了几个 ` case ` 类的特性:
195396
397+ {% tabs case-class %}
398+ {% tab 'Scala 2 and 3' for=case-class %}
399+
196400``` scala
197401// define a case class
198402case class Person (
@@ -216,6 +420,9 @@ val p2 = p.copy(name = "Elton John")
216420p2 // : Person = Person(Elton John,Singer)
217421```
218422
423+ {% endtab %}
424+ {% endtabs %}
425+
219426有关 ` case ` 类的更多详细信息,请参阅 [ 领域建模] [ data-1 ] 部分。
220427
221428[ data-1] : {% link _ zh-cn/overviews/scala3-book/domain-modeling-tools.md %}
0 commit comments