持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
五、类的属性
属性对类的外部提供了一个访问类内部的实例变量的接口,可以通过属性来操作类的实例变量。为类中的一个实例变量提供访问接口的方法非常简单,在 Ruby 中调用方法可以省略括号,就跟调用属性一样,因此可以通过定义一个方法来充当实例变量。
# Ruby 中类的属性的定义
class Person
def name
@name
end
end
person = Person.new
# 通过对象直接调用方法就可以获得实例变量
puts person.name
为类的实例变量追加一个设置器,还要为器创建一个设置方法。设置实例变量值的属性方法比较特殊,命名时需要以 = 为后缀,并且需要设置一个方法参数。
class Person
def name=(val)
@name = val
end
end
p = Person.new
# 通过实例直接设置实例变量的值
p.name = "tom"
属性定义标识符
Ruby 中声明属性的标识符有4个,分别是 attr、attr_reader、attr_writer、 attr_accessor 这四个标识符并不是 Ruby 的关键字,他们只是一些内建的方法,语法如下:
class 类名
attr(attr1, key)
attr_reader :attr1,attr2
attr_writer :attr1,attr2
attr_accessor :attr1,attr2
end
这里的 attr1 是类中实例变量的名称,这里要把 @ 符号换成 :。
attr:根据布尔型数据 Key 的值,定义一个可读写的属性。如果 Key 的值为false,则属性的访问权限为只读。
attr_reader:定义一个或者多个只读的属性
attr_writer:定义一个或者多个只写的属性
attr_accessor:定义一个或者多个可读写的属性
class Dog
attr :name, true
attr_reader :weight, :color
end
六、类的构造方法
Ruby 中构造方法是在实例化时要执行的类方法,而且该方法在创建每一个类的实例的时候都会被调用。
构造方法可以接收 0 个或者多个参数这样就可以在初始化类兑现高德时候直接为该对象的实例变量设置初始值
Ruby 中构造方法的统一名称为 initialize,在调用 new 方法实例化时会调用该方法。
class Car
def initialize(brand, color)
@brand = brand
@color = color
end
def show
puts "品牌为#{@brand},颜色为#{@collect} 的轿车"
end
end
car = Car.new("Tesla", "黑色")
car.show
执行上述代码,输出内容如下:
品牌为Tesla,颜色为 的轿车
方法中使用代码块块
在实际开发中,几个不同的方法中可能会有部分相同的代码,在 Ruby 中可以使用代码块来解决这个问题。
块就是有多行代码组成的一段代码,也叫代码块,代码块的创建非常简单,有两种方法分别是使用 {} 和 do - end。代码块通常都是通过方法的调用来实现代码块中的功能。
Ruby 中也可以将一个代码块作为一个参数传递给方法,然后在方法中使用 yield 关键字调用传入的代码块
def say
puts "Hello"
yield
puts "Bye bye"
end
say do
puts "What do you say?"
end
执行上述代码,输出结果如下:
Hello
What do you say?
Bye bye
还可以为代码块添加参数,然后在方法中使用 yield 关键字调用代码块的时候传入参数,在带参数的代码块中需要以 |arg1, arg2| 的格式传递参数。
def say
name = "Tom"
puts "Hello"
yield name
puts "Bye bye"
end
say do |name|
puts "What do you say?" + name
end
执行上述代码,输出结果如下:
Hello
What do you say?Tom
Bye bye
代码块还可以具有返回值,和方法一样代码块的返回值也是使用最后一个表达式的值作为返回值,而且在方法中也可以获取和使用代码块的返回值
def say
puts yield
end
say do
"Hello, Ruby"
end
执行上述代码,输出结果如下:
Hello, Ruby
七、类的继承
面向对象的一个重要的特性就是继承,继承可以共享父类中的属性和方法,实现代码的复用。
在类的继承中,被继承的类成为基类,也可以成为父类,继承基类的类则成为派生类或者子类,子类继承父类最大的特点是就是可以获取父类中的属性和方法。
Ruby 中继承的实现是使用 < 后面追加一个继承的父类的名称即可
class Animal
puts "这是一个父类"
end
class Dog < Animal
puts "Dog 类继承了 Animal 类"
end
子类可以使用父类中定义的属性
class Animal
def initialize
@leg = 4
end
end
class Dog < Animal
def info
puts "狗狗有 #{@leg} 只腿"
end
end
dog = Dog.new
dog.info
执行上述代码,输出内容如下:
狗狗有 4 只腿
在实例化 Dog 对象的时候,并没有对 Animal 类有任何操作,但是确触发了 Animal 类的 initialize 方法初始化了 @leg 变量,这是因为实例化子类的时候会默认调用父类的构造方法,如果父类还有父类则会一级一级的调用构造方法,Ruby 中子类的构造方法只会调用具有相同参数列表的构造方法,比如下面这种实例化方式就是错误的。
class Animal
# Animal 类
end
class Dog < Animal
def initialize(leg)
@leg = leg
end
end
# 这种实例化方式是错误的
dog = Dog.new
如果子类需要使用与父类有不同参数的构造方法来进行实例化,可以使用 super 关键字主动调用父类的同名构造方法,父类构造方法中的参数可以在 super 关键字后追加。
class Dog < Animal
def initialize(name, color)
super name
@color = color
end
def info
puts "名字:#{@name}, 颜色 #{@color}"
end
end
dog = Dog.new("史努比", "黑色")
dog.info
执行上述代码,输出结果如下:
名字:史努比, 颜色 黑色
方法重写
子类继承父类时,可以对父类的方法进行重写
class Animal
def initialize(name)
@name = name
end
def info
puts "#{@name}"
end
end
class Dog < Animal
def initialize(name, color)
super name
@color = color
end
end
dog = Dog.new("史努比", "黑色")
dog.info
执行以上代码,输出结果如下:
史努比
默认执行的是父类中的 info 方法,当在 Dog 类也增加一个与父类中同名的 info 方法后,再次执行代码
# 其他代码保持不变
def info
puts "名字:#{@name}, 颜色 #{@color}"
end
输出结果如下:
名字:史努比, 颜色 黑色
当对 info 方法进行重写后,执行的就是子类中的 info 方法。
八、作用域
当设计一个类时,类中的属性的访问权限非常重要,如果类中的属性可以被随意访问修改,这将会面临非常大的危险,Ruby 中提供了访问作用域的限制,这种限制分为三个几倍的访问保护:
private方法:私有方法,该方法指定的成员只可以被该类的内部访问,成员对外部是不可见的protected方法:受保护的方法,被该方法指定的成员可以被任何该类的子类访问public方法:公共方法,该方法指定的成员可以被任何类或者对象调用,没有访问限制,且默认的就是public方法
无参数的访问控制方法
如果方法不带参数,在方法前通过关键词设置方法的访问权限
class Animal
def fly # 默认为 public
puts "这是默认的 public 级别的方法"
end
private
def eat
puts "这是定义的 private 级别的方法"
end
protected
def run
puts "这是定义的 protected 级别的方法"
end
public
def jump
puts "这是定义的 public 级别的方法"
end
end
有参方法的访问权限设置
可以将方法名传递给访问权限关键词来设置访问权限
class Animal
def fly # 默认为 public
puts "这是默认的 public 级别的方法"
end
def eat
puts "这是定义的 private 级别的方法"
end
def run
puts "这是定义的 protected 级别的方法"
end
def jump
puts "这是定义的 public 级别的方法"
end
private(:eat)
protected(:run, :jump)
public(:fly)
end
上述类中定义了 eat 方法为 private 方法,run 方法和 jump 方法为 protected 方法,而 fly 方法则为 public 方法。