编程语言的一些基础概念(三):面向对象

本文是 Coursera 课程 ""Programming Languages, Part C"" 的面向对象编程总结,通过 Ruby 深入探讨面向对象编程的概念,如类与方法、可见性、反射、鸭子类型、继承和子类化。讲解了 Ruby 中如何定义和使用对象,以及如何通过子类和继承实现代码复用。此外,还讨论了多继承、Mixin、接口、抽象方法等概念,帮助读者更好地理解和运用面向对象编程。" 46791051,790249,Oracle逻辑复制:廉价高效解决方案,"['数据备份', 'Oracle', '逻辑复制', '方案']
摘要由CSDN通过智能技术生成

在前面两篇中,主要讲了函数式编程语言的一些基础概念。这篇是 Coursera Programming Languages, Part C 的总结,通过 Ruby 介绍面向对象编程里的一些概念。了解这些概念能让你在上手任何一门新的面向对象语言时,都更加得心应手。

虽然用的是 Ruby,但是不会涉及很深的 Ruby,即使不懂 Ruby,读下来应该没问题。对于已经了解面向对象编程的朋友,可以考虑直接跳到子类和继承那部分,或许你会有一些新的启发。

面向对象编程 & Ruby

面向对象编程(Object Oriented Programming)简称 OOP,像 Java,C++ 等语言的主要编程模式都是面向对象的。OOP 主要是通过 对象(Object) 来抽象表示,比如说平面上的一个点,可以抽象表示成 Point(x, y),x,y 表示这个点的横纵坐标。在对象中可以有一些方法(methods) 来具体表示这个对象能做些什么,比如对于一个点,可定义一个 method distFromOrigin ,去求这个点的到原点的距离。

Everything is object in Ruby

Ruby 是动态类型的面向对象语言。Ruby 中所有的表达式都是一个对象,比如数字 1, 2, 3, 4 等是对象,+ 加法是对象的一个方法。Ruby 最出名的是在网页应用的开发,但是因为 Everything is object in Ruby,被选做为这个课程的教学语言。

Class & Methods

在 OOP 中,最基本的就是怎么定义和使用对象以及对象中的方法。

定义 Class 和 Methods

Ruby 中,对象的定义通过 Class 实现。

class Foo
  def m1
    ...
  end
  def m2 (x,y)
    ...
  end
end

这里定义了一个对象 Foo,以及两个方法 m1 和 m2。

调用方法

foo = Foo.new
foo.m1
foo.m2(x, y)

上例是最简单的方法调用。

 e0.m(e1, ..., en)

这是调用方法的抽象表达,可以有另一种理解: 发送消息,e0 是消息的接受者,可以说将 e1 的结果作为参数放在消息 m 里,发送给 e0。

在 Ruby 中,所有表达式都是对象,e1 + e2 实际上是 e1.+ e2 的简写法,e1 调用了 方法 +,e2 是这个方法调用的参数。

定义 实例变量、类变量、类常量、类方法

class Foo
  Const = "constant"

  def initialize
    @foo = 1
    @@bar = 2

  def m1
    ...
  end

  def m2 (x,y)
    ...
  end

  def self.classMethod
    ...
  end
end

上例中,@f 为实例变量 (instance variable) ,@@f 为类变量 (class variable) ,Const 是类常量 (Class constant),classMethod 是类方法。

怎么使用类常量和类方法?

Foo::Const
Foo.classMethod

别名 Aliasing

foo = Foo.new
bar = foo

在这个例子中,bar 是 foo 的别名,他们对应是同一个 object,如果 bar 更改了,foo 也会相对应的更改。在 OOP 中,不像函数式编程里数据不可更改,需要特别注意什么时候用别名,什么时候要新建一个 object。

可见性 Visibility

对象内的变量和方法根据不同的定义方式,对象外不一定可见,可以理解为知不知道它的存在。

class Foo
  def initialize
    @foo = 1

  public
  def m1
    ...
  end

  protected
  def m2
    ...
  end

  private
  def m3
    ...
  end
end

foo = Foo.new
foo.@foo # 报错
foo.m1   # 可见
foo.m2   # 报错
foo.m3   # 报错

实例变量 @foo 在 class Foo 外是不知道它的存在的,foo.@foo 会报错,实例变量只有对象内的方法 m1, m2, m3 可以使用。

这样的设计其实很符合面向对象的概念,Foo 是一个对象,要跟这个对象交流,只能通过发送消息,也就是调用方法的方式。

对象内的方法也可以定义可见性。

  • public,表示对外可见,Ruby 对象默认的模式,在类之外可以调用。
  • protected 和 private 只能在 类和子类都能调用。

Getter & Setter

对象的实例变量对外不可见,但是很多情况下可能会需要实例变量,这个时候可以通过定义 Getter 和 Setter 两个方法来实现实例变量的读写。

# getter
def foo @foo
end

# setter
def foo= x
  @foo = x
end

# simpler way to define getters
attr_reader :y, :z # defines getters

# simpler way to define getters and setters
attr_accessor :x # defines getters and setters

反射 Reflections

反射指的是在程序运行的过程中,能访问、检测和修改它本身的这个对象。比如说可以在运行的过程中去访问这个对象里都有哪些方法,然后动态的去调用这些方法。

鸭子类型 Duck Typing

当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。

def mirror_update point
  point.x = point.x * -1
end

这个方法本意是将一个点 (point) 的 x 值变为 -x,但是所有"像点一样有 x 这个方法"的对象都可以作为参数传入这个函数,这就是所谓的鸭子类型。通常只有动态类型的语言才会支持鸭子类型,但是 Golang 也是有办法实现,这里不展开了。

优缺点

鸭子类型的最大的优点在于代码的重用,同样一段代码,传进的参数只要有那些方法,就能够复用这段代码。但是也带来了缺点,重用使得代码表意不清,我们在用这个方法时,考虑的不是这个方法怎么调用,而是要清楚的了解这个方法的具体实现。举个例子:

def double x
  x + x
end

看到 double 这个函数名,可能最直观的理解就是把数字翻倍,具体的实现 x + x,也可以把两个字符串连在一起。但假如 Ruby 的字符串没有 * 这个方法,具体实现是 2*x 的话,这个函数就不适用于字符串。所以知道一个函数名不够,还得看具体的实现,也挺麻烦的。

Blocks and Using Blocks

这是 Ruby 特有的一个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值