我最近一直在玩Ruby,我似乎无法找到问题的答案。
我有一个类和一个子类。类有一些initialize
方法,子类有它自己的initialize
方法,它应该从它继承一些(但不是全部)变量,并另外添加它自己的变量子类对象。
我的Person
有@name
,@age
和@occupation
。
我的Viking
应该有一个@name
和@age
来自Person
,还有一个@weapon
Person
没有#39; t。 Viking
显然不需要任何@occupation
,也不应该有# doesn't work
class Person
def initialize(name, age, occupation)
@name = name
@age = age
@occupation = occupation
end
end
class Viking < Person
def initialize(name, age, weapon)
super(name, age) # this seems to cause error
@weapon = weapon
end
end
eric = Viking.new("Eric", 24, 'broadsword')
# ArgError: wrong number of arguments (2 for 3)
。
class Person
def initialize(name, age, occupation = 'bug hunter')
@name = name
@age = age
@occupation = occupation
end
end
class Viking < Person
def initialize(name, age, weapon)
super(name, age)
@weapon = weapon
end
end
eric = Viking.new("Eric", 24, 'broadsword')
# Eric now has an additional @occupation var from superclass initialize
class Person
def initialize(name, age, occupation)
@name = name
@age = age
@occupation = occupation
end
end
class Viking < Person
def initialize(name, age, occupation, weapon)
super(name, age, occupation)
@weapon = weapon
end
end
eric = Viking.new("Eric", 24, 'pillager', 'broadsword')
# eric is now a pillager, but I don't want a Viking to have any @occupation
你可以通过以下方式使其发挥作用,但这两种解决方案都不适合我
UITapGestureRecognizer
问题是
1)是否按设计进行,我想根据OOP原则提出一些红衣主教罪?
2)我如何让它以我想要的方式工作(最好没有任何疯狂复杂的元编程技术等)?
答案 0 :(得分:4)
是的,你犯了一个红衣主教罪(显然,你知道它,因为你问的是)。 :)
您正在打破Liskov substitution principle(可能还有其他一些已命名或未命名的规则)。
您应该提取另一个类作为公共超类,它不包含occupation
。这将使一切变得更加清晰和清洁。
答案 1 :(得分:4)
关于参数处理,super关键字可以以三种方式运行:
当没有参数调用时,super会自动将它所调用的方法(在子类中)接收的任何参数传递给超类中的相应方法。
class A
def some_method(*args)
puts "Received arguments: #{args}"
end
end
class B < A
def some_method(*args)
super
end
end
b = B.new
b.some_method("foo", "bar") # Output: Received arguments: ["foo", "bar"]
如果使用空括号(空参数列表)调用,则不会将参数传递给超类中的相应方法,无论调用super的方法(在子类上)是否已接收到任何参数。
class A
def some_method(*args)
puts "Received arguments: #{args}"
end
end
class B < A
def some_method(*args)
super() # Notice the empty parentheses here
end
end
b = B.new
b.some_method("foo", "bar") # Output: Received arguments: [ ]
当使用显式参数列表调用时,它会将这些参数发送到超类中的相应方法,无论调用super的方法(在子类上)是否已接收到任何参数。
class A
def some_method(*args)
puts "Received arguments: #{args}"
end
end
class B < A
def some_method(*args)
super("baz", "qux") # Notice that specific arguments were passed here
end
end
b = B.new
b.some_method("foo", "bar") # Output: Received arguments: ["baz", "qux"]
答案 2 :(得分:0)
这真的是2种方法-自动包含所有属性(只是单词super)和super,您可以在其中选择要传递的参数。执行super()不会选择要传递给父类的参数。
编辑:这是对上述评论的评论,但是当有人刚来时,他们不允许评论...哦。
答案 3 :(得分:0)
您只需在occupation
中为Person Class
传递nil
参数,就可以避免为occupation
中的super()
参数设置默认值。这允许
您使用3个参数Viking.new
来调用(name, age, weapon)
,而无需
必须额外考虑occupation
。
class Person
def initialize(name, age, occupation)
@name = name
@age = age
@occupation = occupation
end
end
class Viking < Person
def initialize(name, age, weapon)
super(name, age, nil)
@weapon = weapon
end
end
eric = Viking.new("Eric", 24, 'broadsword')
p eric
输出Viking:0x00007f8e0a119f78 @ name =“ Eric”,@ age = 24,@ occupation = nil,@ weapon =“ broadsword”