Ruby - 只使用某些参数初始化继承,超级?

时间:2016-05-29 10:18:10

标签: ruby inheritance initialization

我最近一直在玩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)我如何让它以我想要的方式工作(最好没有任何疯狂复杂的元编程技术等)?

4 个答案:

答案 0 :(得分:4)

是的,你犯了一个红衣主教罪(显然,你知道它,因为你问的是)。 :)

您正在打破Liskov substitution principle(可能还有其他一些已命名或未命名的规则)。

您应该提取另一个类作为公共超类,它不包含occupation。这将使一切变得更加清晰和清洁。

答案 1 :(得分:4)

super如何处理参数

关于参数处理,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”