18

と呼ばれるRubyクラスがありLibraryItemます。このクラスのすべてのインスタンスに属性の配列を関連付けたいと思います。この配列は長く、次のようになります

['title', 'authors', 'location', ...]

これらの属性は実際にはメソッドであるとは想定されておらず、aが持つ属性のリストにすぎないことに注意してくださいLibraryItem

次に、のすべての属性を含むが、さらに多くの属性を含む属性の配列を持つ、 LibraryItemcalledのサブクラスを作成したいと思います。LibraryBookLibraryItem

最終的には、LibraryItemそれぞれ独自のバージョンの配列を持つサブクラスがいくつか必要になります@attributesが、それぞれがに追加されLibraryItemます@attributes(たとえば、、、LibraryBookなどLibraryDVDLibraryMap

だから、これが私の試みです:

class LibraryItem < Object
  class << self; attr_accessor :attributes; end
  @attributes = ['title', 'authors', 'location',]
end

class LibraryBook < LibraryItem
  @attributes.push('ISBN', 'pages')
end

これは動作しません。エラーが発生します

undefined method `push' for nil:NilClass

それがうまくいくとしたら、私はこのようなものが欲しいでしょう

puts LibraryItem.attributes 
puts LibraryBook.attributes

出力する

['title', 'authors', 'location']
['title', 'authors', 'location', 'ISBN', 'pages']

(2010年5月2日追加)これに対する1つの解決策は@attributes、単純なインスタンス変数を作成しLibraryBootてから、initializeメソッドにの新しい属性を追加することです(これは、回答の1つでdemasによって提案されました)。

これは確かに機能しますが(実際、私がずっとやってきたことです)、これは最適ではないため、満足していません。オブジェクトが作成されるたびに、これらの不変の配列を作成する必要があるのはなぜですか。

私が本当に望んでいるのは、親クラスから継承できるクラス変数を用意することですが、子クラスで変更しても、親クラスでは変更されません。

4

9 に答える 9

12

別の解決策は、継承されたフックを使用することです。

class LibraryItem < Object
  class << self
    attr_accessor :attributes
    def inherit_attributes(attrs)
      @attributes ||= []
      @attributes.concat attrs
    end

    def inherited(sublass)
      sublass.inherit_attributes(@attributes)
    end
  end
  @attributes = ['title', 'authors', 'location',]
end

class LibraryBook < LibraryItem
  @attributes.push('ISBN', 'pages')
end
于 2012-11-29T16:01:47.007 に答える
9

属性は「固定」で「不変」であると述べているので、オブジェクトが作成されると、その値を決して変更しないことを意味していると思います。その場合、次のようなものが機能するはずです。

class Foo
    ATTRS = ['title', 'authors', 'location']
    def attributes
        ATTRS
    end
end

class Bar < Foo
    ATTRS = ['ISBN', 'pages']
    def attributes
        super + ATTRS
    end
end

attr_accessor配列の内部名を偽装するリーダー メソッドを手動で実装しています (作成するのではなく)。サブクラスでは、祖先クラスのリーダー関数を呼び出し、子クラスに関連付けられた追加フィールドを追加して、それを呼び出し元に返すだけです。attributesユーザーには、これは、サブクラスに追加の値を持つという名前の読み取り専用メンバー変数のように見えます。

于 2010-08-11T22:38:27.870 に答える
5

バージョンとして:

class LibraryItem < Object
  def initialize
    @attributes = ['one', 'two'];
  end
end

class LibraryBook < LibraryItem
  def initialize
   super
   @attributes.push('three')
 end
end

b = LibraryBook.new
于 2010-05-02T07:10:59.743 に答える
4

@Nick Vanderbilt の回答を拡張するには、active_support を使用してこれを行います。これは、まさにこの機能に必要な省略形です。完全な例を次に示します。

require 'active_support/core_ext'

class Foo
  class_attribute :attributes
  self.attributes = ['title','authors','location']
end

class Bar < Foo
  self.attributes = Foo.attributes + ['ISBN', 'pages']
end

puts Foo.attributes.inspect #=> ["title", "authors", "location"]
puts Bar.attributes.inspect #=> ["title", "authors", "location", "ISBN", "pages"]

残念なことに、Ruby がライブラリを必要とせずにこれを達成するのは非常に困難です。それは私がpythonに欠けている唯一のものです。私の場合、active_support gem への依存は気にしません。

于 2012-02-27T04:57:57.677 に答える
4

好奇心から、このようなものは機能しますか?

class Foo
  ATTRIBUTES = ['title','authors','location']
end

class Bar < Foo
  ATTRIBUTES |= ['ISBN', 'pages']
end

これにより、望ましい結果が得られるように見えます。クラス オブジェクトの作成時に ATTRIBUTES 配列が展開され、ATTRIBUTES の値が期待どおりに変化します。

> Foo::ATTRIBUTES
=> ['title','authors','location'] 
> Bar::ATTRIBUTES
=> ['title','authors','location', 'ISBN', 'pages'] 
于 2010-08-11T21:45:06.083 に答える
3

Rails Edge には ActiveSupport の class_attribute メソッドがあります。

于 2010-08-12T02:26:14.227 に答える
2

LibraryBookでは、変数@attributesは新しい独立変数であり、オブジェクトLibraryBookのインスタンス変数であるため、初期化されず、「undefined method ... fornil」というエラーが発生します。
使用する前に、LibraryItem属性のリストで初期化する必要があります。

class LibraryBook < LibraryItem
  @attributes = LibraryItem::attributes + ['ISBN', 'pages']
end
于 2010-05-02T07:42:01.867 に答える
0

これは、配列ではなく文字列 (実際には何でも) 用ですが...

class A
  def self.a
    @a || superclass.a rescue nil
  end

  def self.a=(value)
    @a = value
  end

  self.a = %w( apple banana chimp )
end

class B < A
end

class C < B
  self.a += %w( dromedary elephant )
end

class D < A
  self.a = %w( pi e golden_ratio )
end



irb(main):001:0> require 'test2'
=> true
irb(main):002:0> A.a
=> ["apple", "banana", "chimp"]
irb(main):003:0> B.a
=> ["apple", "banana", "chimp"]
irb(main):004:0> C.a
=> ["apple", "banana", "chimp", "dromedary", "elephant"]
irb(main):005:0> D.a
=> ["pi", "e", "golden_ratio"]
irb(main):006:0> A.a = %w( 7 ) 
=> ["7"]
irb(main):007:0> A.a
=> ["7"]
irb(main):008:0> B.a
=> ["7"]
irb(main):009:0> C.a = nil
=> nil
irb(main):010:0> C.a
=> ["7"]
于 2012-04-11T22:23:58.753 に答える
-1

CONSTANTSを使用することもできます。ただし、チェックはありません。

class LibraryItem < Object
  class << self; attr_accessor :attributes; end
  ATTRIBUTES = ['title', 'authors', 'location',]
end

class LibraryBook < LibraryItem
  ATTRIBUTES .push('ISBN', 'pages']
end
于 2010-05-02T06:26:19.620 に答える