2013-08-30 2 views
1

내가 다른 접근에 의해 반환되는 사용자 정의 객체 (공룡, cacemen 등)의 일부 배열을 포함하는 클래스 game이 같은 game.dinosaurs, 현재 등 game.cavemen루비 사용자 정의 반복자

,이 모든 접근 그냥 내부적으로 저장된 배열을 반환합니다. 그러나 이제는 game.dinosaurs.each_carnivore { ... } 등의 코드를 each_elementeach_attr 반복자와 비슷하게 작성하려면 LibXML::XML::Node에있는 이러한 접근 자에 의해 반환 된 이러한 배열에 사용자 지정 반복 메서드를 추가하고 싶습니다. 그러나 내 접근 자 game.dinosaursgame.cavemen에서 반환 된 객체는 여전히 배열처럼 동작해야합니다.

루비에서는 일반적으로 어떻게됩니까? 접근 자에서 반환 된 객체를 Ruby의 Array 클래스에서 파생 된 사용자 정의 클래스로 설정해야합니까? 또는 Enumerable이 포함 된 맞춤 클래스를 작성해야합니까?

나는 내 컬렉션에 외부 map 또는 select을 사용할 수 있습니다 알고,하지만 난 내 클래스의 사용자가 내부 배열에서만 육식 공룡을 선택하는 반복을 설정하는 방법을 귀찮게 할 필요가 없습니다 것을 내부적으로 이러한 반복을 캡슐화하고 싶어 .

편집 : 내가 반복자를 사용하거나 구현하는 방법을 방법에 대해 물어 아니지만, 어떻게 이전에 그냥 일반 배열 된 객체 단지 일부 사용자 지정 반복자를 추가하는 (그리고 여전히 필요).

+0

내가 [루비에서 실제 객체 지향 디자인] 생각 (http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330) , 8 장은 문제를 정확히 해결하고 몇 가지 옵션을 제시하지만 모든 경우에 적합한 해결책은 없습니다. 이 책을 읽어야합니다 (좋은 소식입니다). 프로젝트에 적합한 아이디어를 찾아야합니다. –

답변

6

그것은 (언제나처럼) 따라 달라집니다. 배열 하위 클래스를 사용할 수 있으며 사용자 정의 클래스를 작성하고 작성 및 위임을 사용할 수 있습니다. 다음은 배열 서브 클래스와 간단한 예제 :

class DinosaurArray < Array 
    def carnivores 
    select { |dinosaur| dinosaur.type == :carnivore } 
    end 

    def herbivores 
    select { |dinosaur| dinosaur.type == :herbivore } 
    end 

    def each_carnivore(&block) 
    carnivores.each(&block) 
    end 

    def each_herbivore(&block) 
    herbivores.each(&block) 
    end 
end 

는 그리고 여기 구성 및 위임 간단한 하나 :

class DinosaurArray 
    def initialize 
    @array = [] 
    end 

    def <<(dinosaur) 
    @array << dinosaur 
    end 

    def carnivores 
    @array.select { |dinosaur| dinosaur.type == :carnivore } 
    end 

    def herbivores 
    @array.select { |dinosaur| dinosaur.type == :herbivore } 
    end 

    def each(&block) 
    @array.each(&block) 
    end 

    def each_carnivore(&block) 
    carnivores.each(&block) 
    end 

    def each_herbivore(&block) 
    herbivores.each(&block) 
    end 
end 

모두 구현은 다음과 같이 사용할 수 있습니다 또한

require 'ostruct' 

dinosaurs = DinosaurArray.new 
dinosaurs << OpenStruct.new(type: :carnivore, name: "Tyrannosaurus") 
dinosaurs << OpenStruct.new(type: :carnivore, name: "Allosaurus") 
dinosaurs << OpenStruct.new(type: :herbivore, name: "Apatosaurus") 

puts "Dinosaurs:" 
dinosaurs.each.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" } 
puts 

그러나 맞춤 반복기가 있습니다.

puts "Carnivores:" 
dinosaurs.each_carnivore.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" } 
puts 

puts "Herbivores:" 
dinosaurs.each_herbivore.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" } 
,210

출력 :

Dinosaurs: 
1. Tyrannosaurus 
2. Allosaurus 
3. Apatosaurus 

Carnivores: 
1. Tyrannosaurus 
2. Allosaurus 

Herbivores: 
1. Apatosaurus 
+0

흠 .. 그래서'Array'에서 반환 된 객체의 클래스를 파생시킬 필요가 있다고 생각합니다. 감사.나는 그것이 최선의 해결책인지 확실하지 않았다. – SasQ

+0

그것은, 구성 및 위임에 따라 달라질 수도 있습니다 :) – Stefan

+0

@SasQ 다른 구현을 추가했습니다 – Stefan

1

이 작업은 루비 블록을 사용하여 수행 할 수 있습니다. 여기 Read more

간단한 예 :

class Game 

    def initialize 
    @carnivoures = [1,2,3] 
    end 

    def each_carnivoures 
    @carnivoures.each do |carni| 
     yield carni 
    end 
    end 

end 

Game.new.each_carnivoures{ |c| p c} 
+0

죄송합니다, 블록을 사용하거나 구현하는 방법에 대해 묻지 않습니다. 이전에 평범한 배열을 반환하고 많은 코드가 그것에 의존하는 접근 자에서 반환 된 객체에 이러한 사용자 지정 반복기를 추가하는 것이 가장 좋은 방법인지 묻습니다. 난 그냥 추가 된 반복 메서드를 반환 된 배열에 어떻게 든 추가 할 * 싶습니다. 내 질문이 업데이트되었으므로 지금은 더 명확 해지기를 바랍니다. – SasQ