Scala 的组合和继承

Scala 的组合和继承

组合和继承

组合意味着一个类持有另外一个类的引用,来帮助此类来完成任务
继承是父/子类的关系

组合和继承是根据已有的类来定义新类的两种方式。当你倾向于代码的重用,你应该选择组合而不是继承。因为继承会导致脆弱基类(fragile base class)问题,很容易破坏子类的实现

询问自己,继承的模型是否是is a关系,客户端是否想把子类当做超类来使用,如果是这种is a关系,则需要使用继承;如果是has a关系,则使用组合。从设计模式上讲,优先使用组合而非继承

抽象类

使用abstract来修饰一个类,即可将此类申明为抽象类

abstract class Foo

需要注意的地方:

1.一个类含有抽象的成员,此类必须要声明为抽象
2.一个类声明为抽象,则此类可以含有抽象成员
3.在抽象类中,抽象成员不必使用abstract修饰符

也就是说,含有抽象成员是声明一个类为抽象类的充分条件

无参方法

定义一个方法,该方法没有参数列表(paremeter list),该方法就是无参方法。如果一个方法含有空的圆括号,叫做空参方法(empty-param methods)

def width: Int // parameterless methods.
def width() : Int // empty-param methods.

不论是方法没有参数,还是方法访问可变状态(只读)时,都推荐使用无参方法。这个约定支持统一访问原则(uniform access principle)客户端代码不受你决定将一个属性实现为字段还是方法的影响

总结下来,在 Scala 中鼓励使用不带参数,当没有副作用的时候,推荐使用无参方法。反过来,你不应该定义有副作用的无参方法,那样会给你的调用方造成很多的困扰。如果你调用一个方法具有副作用,那么也应该带上空括号(Empty parentheses)。

扩展类

使用extends关键字来对类进行扩展,也就是所谓的继承

继承(Inheritance)意味着超类的所有成员也会成为子类的成员,但是有两点除外:

1.超类的私有成员无法继承到子类中
2.如果子类中有实现和超类一样签名的成员,那么超类的该成员也无法继承到子类中,这也就是所谓的重写(overrides)

如果超类中的成员是抽象的,在子类中是具体的(concrete),叫做子类实现了超类的抽象成员

重写方法和字段

统一访问原则的一个方面,就是Scala对待字段和方法更加的统一。在 Scala 中,字段和方法属于同一个命名空间(就是说在 Scala 中,禁止在同一个类中出现同名的方法和字段),这就为字段重写为一个无参方法提供了可能

总的来说,Scala 拥有两个命名空间(Java 含有四个,字段、方法、类型、包)。

  • 值(字段,方法,包和单例对象)
  • 类型(类和特质)

所以可以在 Scala 中,将一个无参方法重写为一个字段

abstract class Foo {
  def bar: Int
}

class FooX extends Foo {
  val bar = 1
}

参数化字段

使用参数化字段可以消灭代码的坏味道(code smell)
要区别于类参数,其对外不可见

关于参数化字段的用法:

1.可以使用 var 来进行修饰,表示该字段是可以重新赋值的(reassignable)
2.可以添加修饰符(modifiers),比如 private,protected,override 到参数化字段

使用参数化字段来重写无参方法时需要注意:该参数化字段不能使用var修饰,只能使用val,同样也不能改变原来方法的可见性(private, protected)

abstract class Animal {
  def sound: String
}

class Cat(val sound: String) extends Animal

class Dog(
        private val color: String,
        protected val weight: Int, 
        val sound: String
      ) extends Animal

class Garfield(
        var color: String, 
        override val sound: String
      ) extends Cat(sound)

val cat = new Garfield("Yellow", "Wow")

println(cat.sound)
println(cat.color)

重写操作符

在 Scala 中,如果对父类的一个具体方法进行重写,则必须要使用override修饰符,如果是对父类的抽象方法进行重写,则override则是可选的,如果不是重写或者实现父类的成员,那么override修饰符是禁止使用的
关于重写的上述约定,在系统演进(evolution)过程中非常重要

当然override也会带来脆弱基类(fragile base class)的问题,就是在基类中添加已经在客户端子类中已有的方法,将会导致编译出错

多态和动态绑定

多态可以从技术上理解为动态绑定。也就是说实际上具体哪个方法实现的调用取决于运行时的对象,而不是变量类型或者表达式

最终成员

如果想要在继承层次中,使得某个成员不能被子类重写,可以使用final修饰符
如果想要整个类都不被子类化,可以在类定义上添加final修饰符

工厂对象

工厂对象就是包含那些构建其他对象的对象。客户端可以使用工厂方法来构建对象,而不是直接使用new关键字来进行构建

使用工厂对象来构建对象会有很多的好处:

1.将创建过程中心化且隐藏对象的构建细节
2.为将来提供更多的机会来修改实现代码而不至于破坏客户端代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GettingReal

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值