在 Day2 提到过,Ruby
为单一继承的语言。若我们要实现多重继承的话,我们在 Day14 提到可以使用mixin
。今天要介绍的是 Ruby
程序语言内,Class
级别的继承
# 後台退货单controller
module Admin
class ReturnOrdersController < ApplicationController
# Day14 提到的Datatable module
include Datatable
end
end
class Admin::ApplicationController < ApplicationController
# admin 後台动作
end
Rails的专案中,我们一般会在後台管理介面的内容放在admin
,并给予NameSpace
为 Admin
。
从上方的关系我们看到,Admin::ReturnOrdersController
继承了 Admin::ApplicationController
,而 Admin::ApplicationController
则继承了ApplicationController
。我们用以下表格说明彼此的权责分工
Class in Controller | 说明 |
---|---|
Admin::ReturnOrdersController | 後台退货单 Controller |
Admin::ApplicationController | 後台管理介面相关的 Controller 的动作 |
ApplicationController | 所有 Controller 的动作 |
Admin::ReturnOrdersController
的 ancestors
一共有下面这些。
Admin::ReturnOrdersController.ancestors
#=> [Admin::ReturnOrdersController, Datatable, Admin::ApplicationController, #<Module:0x00007fe5cf522800>, ApplicationController, ..., Object, ..., Kernel, BasicObject]
我们分别可以看到 Admin::ReturnOrdersController, Datatable, Admin::ApplicationController, ApplicationController
在继承链的位置。
我们用 ancestors
的继承链,可以看到继承关系如下!
class A
end
class B < A
end
class C < B
end
C.ancestors
#=> [C, B, A, Object, Kernel, BasicObject]
我们习惯会称 B为A的子类别SubClass
、C为B的子类别。如果看到外国文章提到SubClass
,记得就是指这种关系。
在使用继承的方法时,可以使用#inherited
hook,我们可以在#inherited
新增实体方法跟类别方法。
class A
def self.inherited(subclass)
puts "Singleton class just got subclassed by #{subclass}"
#=> add instance method
subclass.class_eval do
end
#=> add class method
subclass.instance_eval do
end
end
end
class B < A
end
#=> Singleton class just got subclassed by B
当我们使用了super
的关键字,就可以取得继承链上一层的内容。换句话说,若我们在继承链写super
,则可以避免覆写方法。
下列例子中,StrongWarrior
继承了战士的属性。
module Sword
mattr_accessor :material, default: :silver
def sword_name
[material.capitalize, 'Sword'].join(' ')
end
end
class Warrior
include Sword
attr_accessor :height, :weight, :tag
def initialize(height = nil, weight = nil)
@weight = weight
@height = height
end
def warrior_info
{
height: height,
weight: weight,
tag: tag
}
end
end
super
不带参数,代表概括继承。首先,我们使用没有参数的super
。
class StrongWarrior < Warrior
def initialize(height, weight)
super
@tag = 'Strong'
end
end
warrior = StrongWarrior.new(172, 72)
warrior.warrior_info #=> {:height=>172, :weight=>72, :tag=>"Strong"}
super
带参数的用法也可以
class WeekWarrior < Warrior
def initialize(height, weight)
super(height)
@tag = 'Week'
end
end
warrior = WeekWarrior.new(172, 72)
warrior.warrior_info #=> {:height=>172, :weight=>nil, :tag=>"Week"}
带入空括号,代表不带参数进去。
class NilWarrior < Warrior
def initialize(height, weight)
super()
@tag = 'Week'
end
end
warrior = NilWarrior.new(172, 72)
warrior.warrior_info #=> {:height=>nil, :weight=>nil, :tag=>"Week"}
⭐️ 由此可以知道,super
, super()
是完全不一样的概念
super
可以在SubClass
的各种方法内使用。
class SuperWarrior < Warrior def initialize(height, weight) super @tag = 'Week' end def warrior_info { **super, a: 1, b: 2 } endendwarrior = SuperWarrior.new(172, 72)warrior.warrior_info #=> {:height=>172, :weight=>72, :tag=>"Week", :a=>1, :b=>2}
SuperWarrior#warrior_info
的概念是将原本的Warrior#warrior_info
额外填写其他资料。
此外,Super
可以搭配yield
来使用喔!
class Warrior
attr_accessor :height, :weight, :tag
def initialize(height = nil, weight = nil)
@weight = weight
@height = height
end
def foo
block_given? ? yield : 'foo'
end
end
class YieldWarrior < Warrior
def initialize(height, weight)
super
@tag = 'Yield'
end
def foo
[super {"I am a good boy"}, "am I?"].join(', ')
end
end
warrior = YieldWarrior.new(172, 72)
warrior.foo #=> "I am a good boy, am I?"
继承的基本概念是这样,接着我们讲Bonus的主题 ➡️ 如何取得该类别的各种方法
Day10-15 中,已经介绍了几个方法
ancestors
instance_methods
singleton_methods
我们可以参考以下的方式筛选查看方法
User.instance_methods
#=> [:name_in_email, :email_upcase, ..., ..., ...]
#======= false ➡️ 不包含 ancestors 的方法 =======#
User.methods(false)
User.instance_methods(false)
#======= 用减集合来排除多余的方法 =======#
User.methods - ActiveRecord::Base.methods
#======= grep =======#
string = "This is my IT challenge for 15th day."
string.methods.grep(/.!/).sort
#======= 取得 ancestors =======#
A.singleton_methods - A.singleton_methods(false)
这两天分别讲到module
, class
级别的继承,大致上已经介绍了一个段落。
明天会开始介绍常用的设计流程
预处理器是什麽? 透过不同的编译方式,最後都会产生成 CSS 的样式,在变成 CSS 前,这些预处理...
tcpdump Introduction wiki: tcpdump 是一个执行在命令列下的嗅探工具...
前言 这篇将介绍 boxenn 与 DAL 层的依赖关系和介面。 简易 Class Diagram ...
这是铁人赛的最後一篇文章,我想在这个结尾分享为什麽我会写这个主题,这是因为几个月前的某一天我正在与跨...
此篇会简单介绍 FlexBox,以及 flex container 的排列方向设置、对齐设置技巧。 ...