前言
面相对象程序设计有四大要素, 抽象
、封装
、继承
、多态
① 抽象
①-① Why
抽象是为了什么?
一句话,抽象是为了
分门别类
.这样才能隔离问题中的关注点,降低研究问题的复杂度.
程序设计中我们为什么要学习抽象?
程序设计中也需要分门别类,OOP就是基于抽象之上构建.比如你要理解封装,就要知道抽象的意义,封装只不过是抽象概念上进行加强.更细致的划分了方法的访问权限
①-② 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() {
}
}
①-③ What
抽象概念的本质就是分门别类,抽取共性,形成概念.
② 封装
②-① Why
OOP编程中,我们经常需要隐藏实现细节
,对数据进行校验,保证数据的合法性
.这时候就需要用到封装这个特性.
②-② 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
}
}
②-③ What
封装就是分析出类,将抽象出来的属性和方法放在一个类里,暴露该暴露的接口,过滤和校验相应的输入数据,隐藏内部的复杂性, 这就是封装.
②-④ Details
- Scala中声明属性的时候就会生成和setter和getter功能一样的方法,只是不符合JavaBean规范.setter->
属性名_$eq(xxx)
, getter->属性名()
- scala中可以直接使用逗号访问属性,其本质是调用对应的setter和getter方法.(setter->
属性名_$eq(xxx)
, getter->属性名()
)
③ 继承
③-① Why
继承主要为了解决代码复用的问题,提现的是别人有,我拿来用的理念.
③-② 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")
}
}
③-③ What
- 继承本质逻辑上说是is-a的关系.我们对现实世界的认知,依赖于我们给事物们取的“名字”,有了这些名字,人类对世界的思考以及交流才变得可能,这些名字,有着抽象度大小的区别,例如赤兔马,既是马,也是动物.
③-④Details
- 开发中要
慎用
继承,多用
组合,组合也能复用别人的代码,而且不像继承耦合得太深(父类一变,只类就会受影响,这个影响可能是几千个类). - 子类继承父类所有属性和方法.能不能访问则看权限修饰
- 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 抽象类/接口 {
// 实现对应的方法和属性
}
③-X Scala中的抽象类
③-① Why
抽象类的出现主要是有些类并不需要立马实现相应的方法或者初始化变量.而只是定义好一个类的骨架,即描述
好要做的事情,具体的实现延迟到子类中
③-② How
语法和规则
抽象类的语法,必须用abstact修饰class.
- 类中没有方法体的方法,没有初始化的字段都为抽象
- 只要类中有抽象成员,那么这个类必须用abstact修饰为抽象类,旦抽象类不一定要包含抽象成员(当然不包含还设计成抽象类就是傻子)
abstract class Person() {
var name :String
def printName
}
③-③ Details
- 子类继承抽象类,要么全部实现抽象成员.要么也声明为抽象类.
- 子类对抽象类的方法是实现,不是重写,无需加override标记.
- 抽象方法不能用final和private修饰,这样子类无法实现.永远为抽象,永远没法用.
网友评论