前言
面相对象程序设计有四大要素, 抽象, 封装, 继承, 多态
1 抽象
1-1 Why
抽象是为了什么?
一句话, 抽象是为了分门别类. 这样才能隔离问题中的关注点, 降低研究问题的复杂度.
程序设计中我们为什么要学习抽象?
程序设计中也需要分门别类, OOP 就是基于抽象之上构建. 比如你要理解封装, 就要知道抽象的意义, 封装只不过是抽象概念上进行加强. 更细致的划分了方法的访问权限
1-2 How
语法和规则
抽取公共的属性
抽取公共的行为为方法
如下图, 我们可以抽象出动物的概念
image.PNG
用代码表示抽象出的动物
- class Animal(inColor :String, inAge :Int, inWeight :Int) {
- var color :String = inColor
- var age :Int = inAge
- var weight :Int = inWeight
- def eat() {
- }
- }
- 1-3 What
抽象概念的本质就是分门别类, 抽取共性, 形成概念.
2 封装
2-1 Why
OOP 编程中, 我们经常需要隐藏实现细节, 对数据进行校验, 保证数据的合法性. 这时候就需要用到封装这个特性.
2-2 How
语法和规则
将属性进行私有化
提供一个公共的 set 方法, 用于对属性判断并赋值
- def setXxx(参数名 : 类型) : Unit = {
- // 加入数据验证的业务逻辑
属性 = 参数名
}
提供一个公共的 get 方法, 用于获取属性的值
def getXxx() : 返回类型 = {
return 属性
- }
- Demo
- object EncapDemo {
- def main(args: Array[String]): Unit = {
- val stu = new Student
- stu.setScore(120)
- println(s"student score = ${stu.score}")
- }
- }
- class Student {
- var score : Double = 0.0
- def setScore(inScore :Double): Unit = {
- if (inScore> 100) score = 100
- else if (inScore <0 ) score = 0
- else score = inScore
- }
- }
- 2-3 What
封装就是分析出类, 将抽象出来的属性和方法放在一个类里, 暴露该暴露的接口, 过滤和校验相应的输入数据, 隐藏内部的复杂性, 这就是封装.
2-4 Details
Scala 中声明属性的时候就会生成和 setter 和 getter 功能一样的方法, 只是不符合 JavaBean 规范. setter-> 属性名_$eq(xxx) , getter-> 属性名 ()
scala 中可以直接使用点号访问属性, 其本质是调用对应的 setter 和 getter 方法.(setter-> 属性名_$eq(xxx) , getter-> 属性名 ())
所以现在很多框架, 因为上面的这个特性, 可以直接对属性进行反射.
3 继承
3-1 Why
继承主要为了解决代码复用的问题, 提现的是别人有, 我拿来用的理念.
3-2 How
规则和语法
class 子类名 extends 父类名 {
- // 类体
- }
- Demo
演示 Student 类继承 Person 类, 并添加 study 方法表示学生的学习行为
- object ExtendsDemo {
- def main(args: Array[String]): Unit = {
- val stu = new Student("lisi", 25)
- stu.showInfo()
- stu.study()
- }
- }
- class Person(inName :String, inAge :Int) {
- var name :String = inName
- var age :Int = inAge
- def showInfo(): Unit = {
- println(s"name = ${name}, age = ${age}")
- }
- }
- class Student(inName :String, inAge :Int) extends Person(inName : String, inAge :Int) {
- def study(): Unit = {
- println(s"${name} studing")
- }
- }
- 3-3 What
继承本质逻辑上说是 is-a 的关系. 我们对现实世界的认知, 依赖于我们给事物们取的 "名字", 有了这些名字, 人类对世界的思考以及交流才变得可能, 这些名字, 有着抽象度大小的区别, 例如赤兔马, 既是马, 也是动物.
3-4Details
开发中要慎用继承, 多用组合, 组合也能复用别人的代码, 而且不像继承耦合得太深 (父类一变, 只类就会受影响, 这个影响可能是几千个类).
子类继承父类所有属性和方法. 能不能访问则看权限修饰
scala 规定, 重写父类一个非抽象方法需要用 override 修饰符, 调用超类的方法使用 super
在 Student 类中增加如下方法和成员变量
- var address :String = inAddress
- override def showInfo() {
- println(s"name = ${name}, age = ${age} address=${address}")
- }
测试某个对象是否属于某个给定的类, 可以用 isInstanceOf 方法. asInstanceOf 方法将引用转换为子类的引用. classOf 获取对象的类名.
- object ExtendsDemo2 {
- def main(args: Array[String]): Unit = {
- println(classOf[String]) // 等价于 String.class
- println("Hello".isInstanceOf[String]) // 等价于 isInstanceOf(object)
- val stu = new Student("lisi", 23, "beijing")
- stu.study()
- val person = stu.asInstanceOf[Person] // 等价于 (Person)stu
- person.showInfo()
- }
- }
Scala 中超类的构造.(类有一个主构器和任意数量的辅助构造器, 而
每个辅助构造器都必会调用到主构造器
, 可以是间接也可以是直接)
- object ExtendsDemo3 {
- def main(args: Array[String]): Unit = {
- val son = new Son("weipeng")
- }
- }
- class Parent {
- var name :String = _
- println("parent Constructor")
- }
- class Son() extends Parent() {
- println("son primary Constructor")
- def this(inName :String) {
- this
- this.name = inName
- println("son sub Constructor")
- }
- }
打印输出
- parent Constructor
- son primary Constructor
- son sub Constructor
Scala 中的复写字段. Java 中不可以复写字段, 旦 Scale 中支持对字段的复写.
def 只能重写另一个 def(即: 方法只能重写另一个方法)
var 只能重写另一个抽象的 var 属性
val 只能重写另一个 val 或 重写不带参数的方法 (函数)
- class AObject {
- val name :String = "A"
- def sal(): String = {
- "AObject sal method"
- }
- }
- class BObject extends AObject {
- override val name :String = "B"
- override val sal :String= "1000"
- }
其底层对应生成了一个公共的 getter 方法
- public String sal()
- {
- return this.sal;
- }
- private final String sal = "1000";
匿名对象的创建方式和 Java 基本一样.
new 抽象类 / 接口 {
- // 实现对应的方法和属性
- }
3-X Scala 中的抽象类
3-1 Why
抽象类的出现主要是有些类并不需要立马实现相应的方法或者初始化变量. 而只是定义好一个类的骨架, 即描述
好要做的事情, 具体的实现延迟到子类中
3-2 How
语法和规则
抽象类的语法, 必须用 abstact 修饰 class.
类中没有方法体的方法, 没有初始化的字段都为抽象
只要类中有抽象成员, 那么这个类必须用 abstact 修饰为抽象类, 旦抽象类不一定要包含抽象成员 (当然不包含还设计成抽象类就是傻子)
- abstract class Person() {
- var name :String
- def printName
- }
- 3-3 Details
子类继承抽象类, 要么全部实现抽象成员. 要么也声明为抽象类.
子类对抽象类的方法是实现, 不是重写, 无需加 override 标记.
抽象方法不能用 final 和 private 修饰, 这样子类无法实现. 永远为抽象, 永远没法用.
来源: http://www.jianshu.com/p/5bae278b3966