一、函数式对象

1.1  rational类的规格和创建

  • Rational类来源于有理数(rational number),来表示n(分子)/d(分母)的数字,同时对有理数的运算(加减乘除)建模,还具备归元化的特点。

下例子没有建模的:

scala> val oneHalf=new Rational(1,2)
oneHalf: Rational = 1/2
scala> val twoThirds=new Rational(2,3)
twoThirds: Rational = 2/3
scala> (oneHalf /7)+(1 twoThirds)
<console>:13: error: value / is not a member of Rational
(oneHalf /7)+(1 twoThirds)
^
<console>:13: error: value twoThirds is not a member of Int
(oneHalf /7)+(1 twoThirds)
scala> (oneHalf /7)+1
<console>:13: error: value / is not a member of Rational
(oneHalf /7)+1

  

  • Rational的创建,类名后的括号里的n、d两个类参数。Scala编译器会收集这两个类参数并创造出带同样的参数的主构造器
Class Rational(n:Int,d:Int)
scala> class Rational(n:Int,d:Int){
| println("Created"+n+"/"+d)
| }
defined class Rational scala> new Rational(1,2)
Created1/2
res21: Rational = Rational@6fbfd6ed

默认情况下,Rational类继承了java.lang.Object类的toString实现,只会打印类名、@和十六进制数。

  • 为了打印出具体的分子分母,可以通过重载Rational类的toString实现。
scala> class Rational(n:Int,d:Int){
| override def toString = n+"/"+d }
defined class Rational scala> val x =new Rational(1,3)
x: Rational = 1/3

  

1.2   rational先决条件

面向对象编程的优点之一是它允许你将数据封装在对象之内以确保数据在整个生命周期中的有效性。意味着必须确保rational类建有理数的有效性,

即分母不为0,故应该为主构造器定义一个先决的条件,说明d不为0,先决条件是对传递给方法或者构造器的值的限制,是调用者必须满足的需求。

  • 一种方法是使用require方法,如:
scala> class Rational(n:Int,d:Int){
| require(d!=0)
| override def toString = n+"/"+d
| }
defined class Rational scala> new Rational(2,0)
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:268)
... 29 elided scala> new Rational(2,9)
res13: Rational = 2/9

注:Require方法带来一个布尔型参数。如果传入的值为真,require将正常返回,反之,require将抛出IllegalArgumentException防止对象被构建。

1.3  添加字段

为了保持Rational的不可变性,add方法不能把传入的有理数加到自己身上,而是必须创建并返回全薪的Rational累加值。

class Rational(n:Int,d:Int){
require(d!=0)
val number:Int=n
val denom:Int=d
override def toString =number + "/"+denom
def add(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
}
scala>val oneHalf=new Rational(1,2)
oneHalf: Rational = 1/2

  

1.4  自指向this

关键字this指向当前执行方法被调用的对象实例,或者如果使用在构造器里的话,就是正被构建的对象实例。如下:

scala> class Rational(n:Int,d:Int){
| require(d!=0)
| val number:Int=n
| val denom:Int=d
| override def toString =number + "/"+denom
| def add(that:Rational):Rational=
| new Rational(
| number*that.denom+that.number*denom,
| denom*that.denom
| )
| def lessThan(that:Rational)=this.number*that.denom<that.number*this.denom
| def max(that:Rational)=if(this.lessThan(that)) that else this
| }
defined class Rational scala> new Rational(1,2)
res42: Rational = 1/2
scala> new Rational(1,4)
res43: Rational = 1/4
scala> res43.lessThan(res42)
res44: Boolean = true
scala> res43.max(res42)
res45: Rational = 1/2

  

1.5  辅助构造器

  • Scala里主构造器之外的构造器被称为辅助构造器。作用:对5/1,能够写成Rational(5),这就需要给Rational添加辅助构造器预先设置分母为1
class Rational(n:Int,d:Int){
require(d!=0)
val number:Int=n
val denom:Int=d
def this(n:Int) =this(n,1)//辅助构造器 override def toString =number + "/"+denom
def add(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
}

  

1.6  私有字段和方法

  • 为了约简化(归元化)为无差别的最简形式,即(66/42---->11/7),引入私有的最大公约数的字段和方法。
 class Rational(n:Int,d:Int){
require(d!=0)
private val g =gcd(n.abs,d.abs)
val number=n/g
val denom=d/g
def this(n:Int) =this(n,1)
def add(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
override def toString =number + "/"+denom
private def gcd(a:Int,b:Int):Int =
if(b==0) a else gcd(b,a%b)
} scala> new Rational(99,66)
res23: Rational = 3/2

  

17. 定义操作符

在Scala中用常用的数学符号+替换add方法,因为Scala里+是合法的标识符,能够用+定义方法名。

class Rational(n:Int,d:Int){
require(d!=0)
private val g =gcd(n.abs,d.abs)
val number=n/g
val denom=d/g
def this(n:Int) =this(n,1) def +(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
override def toString =number + "/"+denom
private def gcd(a:Int,b:Int):Int =
if(b==0) a else gcd(b,a%b)
}

  

结果如下:

scala> new Rational(4,9)
res30: Rational = 4/9
scala> new Rational(4,8)
res31: Rational = 1/2
scala> res30+res31
res32: Rational = 17/18

  

1.8. 方法重载

在上面定义的都是有理数的运算,引入整数和有理数之间的运算,使用方法重载。

class Rational(n:Int,d:Int){
require(d!=0)
private val g =gcd(n.abs,d.abs)
val number=n/g
val denom=d/g
def this(n:Int) =this(n,1)
def +(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
def +(i:Int):Rational=
new Rational(
number+i*denom,denom
)
override def toString =number + "/"+denom
private def gcd(a:Int,b:Int):Int =
if(b==0) a else gcd(b,a%b)
}

  

结果如下:

scala> new Rational(1,2)
res37: Rational = 1/2
scala> 2
res38: Int = 2
scala> res37+res38
res39: Rational = 5/2

  

Scala实践3的更多相关文章

  1. Scala实践14

    1.Scala的future 创建future import scala.concurrent._ import ExecutionContext.Implicits.global object Fu ...

  2. Scala实践13

    1.隐式参数 方法可以具有隐式参数列表,由参数列表开头的implicit关键字标记.如果该参数列表中的参数没有像往常一样传递,Scala将查看它是否可以获得正确类型的隐式值,如果可以,则自动传递. S ...

  3. Scala实践12

    1.内部类和抽象类型成员作为对象成员 内部类 在Scala中,可以让类将其他类作为成员.这些内部类是封闭类的成员.在Scala中,这样的内部类绑定到外部对象.假设希望编译器在编译时阻止我们混合哪些节点 ...

  4. Scala实践11

    1.1泛型类 泛型类是将类型作为参数的类.它们对集合类特别有用. 定义泛类型:泛型类将类型作为方括号内的参数[].一种惯例是使用字母A作为类型参数标识符,但是可以使用任何参数名称. class Sta ...

  5. Scala实践10

    1.模式匹配 模式匹配是一种根据模式检查值的机制.它是switch(Java中语句)的更强大版本,它同样可以用来代替一系列if / else语句. 句法 匹配表达式具有值,match关键字和至少一个c ...

  6. Scala实践9

    1.特征 Traits用于在类之间共享接口和字段.它们类似于Java 8的接口.类和对象可以扩展特征,但是特征不能被实例化,因此没有参数. 定义一个特征 最小特征只是关键字trait和标识符: tra ...

  7. Scala实践6

    1  if表达式 Scala中if...else..表达式是有返回值的,如果if和else返回值类型不一样,则返回Any类型. scala> val a3=10 a3: Int = 10 sca ...

  8. Scala实践8

    1.1继承类 使用extends关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法. class Person { var name = "zhangsan" ...

  9. Scala实践7

    一.类 1.1简单类和无参方法 类的定义通过class关键字实现 scala> class Dog { | private var leg = 4 | def shout(content: St ...

  10. Scala实践5

    一.Scala的层级 1.1类层级 Scala中,Any是所其他类的超类,在底端定义了一些有趣的类NULL和Nothing,是所有其他类的子类. 根类Any有两个子类:AnyVal和AnyRef.其中 ...

随机推荐

  1. Python--day24--复习

  2. python基础十之装饰器

    1,装饰器的形成 编程原则:开放封闭原则. 开放:对扩展是开放的 封闭:对修改是封闭的 因为修改是封闭的,所以为了对函数进行功能的扩展,就使用装饰器! 2,装饰器的定义 # wrapper就是一个装饰 ...

  3. 2018-7-31-C#-判断两条直线距离

    title author date CreateTime categories C# 判断两条直线距离 lindexi 2018-07-31 14:38:13 +0800 2018-05-08 10: ...

  4. java Class中得到构造方法Constructor、方法Method、字段Field

    常用方法: Constructor类用于描述类中的构造方法: Constructor<T> getConstructor(Class<?>... parameterTypes) ...

  5. dotnet 启动 JIT 多核心编译提升启动性能

    用2分钟提升十分之一的启动性能,通过在桌面程序启动 JIT 多核心编译提升启动性能 在 dotnet 可以通过让 JIT 进行多核心编译提升软件的启动性能,在默认托管的 ASP.NET 程序是开启的, ...

  6. dotnet 控制台读写 Sqlite 提示 no such table 找不到文件

    在使用 dotnet 读写 Sqlite 可以通过 EF Core 的方法,但是在 EF Core 创建的数据库可能和读写的数据库不是相同的文件 在我运行代码的时候发现在通过迁移创建数据库,创建的文件 ...

  7. PowerShell 通过 WMI 获取系统服务

    本文告诉大家如何通过 WMI 获取系统服务 通过 Win32_Service 可以获取系统启动的服务 Get-WmiObject Win32_Service | Format-List Caption ...

  8. samba 部署与实验

    一.本地用户登录 1.本地用户验证(Samba服务器默认的安全级别,用户在访问共享资源之前必须提供用户名和密码进行验证) 拓展:tdbsam:该方式是使用一个数据库文件来验证.数据库文件叫passdb ...

  9. 【Jenkins】pipeline-hello-world项目

    1.New Item 2.Pipeline Definition 3.Build Error 4.Solution 5.Console Output

  10. schema list validator --python cerberus

    工作中需要对如下json结构进行验证: "ActiveStatus" : [ { "effectiveDates" : { "effectiveFro ...