IT

루비 상속과 믹스 인

lottoking 2020. 7. 9. 07:54
반응형

루비 상속과 믹스 인


루비에서는 여러 믹스 믹스 인을 포함 할 수있는 하나의 클래스 만 확장 믹스 인이 상속되는 것입니다.

내 질문 : 유용 확장 / 포함 해야하는 코드를 작성하는 왜 클래스로 만들 것입니까? 아니면 달리 말하면 왜 항상 모듈로 만들지 보장겠습니까?

클래스를 원하는 한 가지 이유 만 생각할 수있는 클래스를 인스턴스화해야하는 경우입니다. 그러나 ActiveRecord :: Base의 경우 직접 인스턴스화하지 않습니다. 대신 모듈이 아니어야?


나는 단지 이 주제에 대해 읽어 잘 접지 Rubyist (그런데 좋은 책). 더 나은 설명을 해주 것보다 인용하겠습니다.


단일 규칙이나 공식이 항상 올바른 디자인을 만들지 만들었습니다. 그러나 클래스 대 모듈 결정을 내릴 때 몇 가지 고려 사항을 명심하는 것이 유용합니다.

  • 모듈에는 인스턴스가 없습니다. 엔터티 또는 사물은 일반적으로 클래스에서 가장 잘 모델링되고 엔터티 또는 사물의 특성 또는 속성은 모듈에서 가장 잘 캡슐화됩니다. 이에 따라 4.1.1 절에서 언급 한 내용 같이 클래스 이름은 명사 인 경향 사 (스택 대 스택 형용).

  • 클래스는 하나의 슈퍼 클래스 만이 원하는만큼 많은 모듈을 사용할 수 있습니다. 상속을 사용하는 경우 합리적인 수퍼 클래스 / 서브 클래스 관계 작성을 우선시하십시오. 클래스의 유일한 수퍼 클래스 관계를 사용하여 클래스에 여러 특성 세트 중 하나 일 수있는 것을 부여하십시오.

한 가지 예에서 다만 규칙을 요약하면 다음과 같이하지 않습니다.

module Vehicle 
... 
class SelfPropelling 
... 
class Truck < SelfPropelling 
  include Vehicle 
... 

오히려 다음을 수행해야합니다.

module SelfPropelling 
... 
class Vehicle 
  include SelfPropelling 
... 
class Truck < Vehicle 
... 

두 번째 버전은 훨씬 더 깔끔하게 모델링합니다. 트럭은 차량의 의미에 해당하는 반면, SelfPropelling은 차량의 특성 (적어도이 세계 모델에서 우리가 관심을 모든 것)입니다. 이것은 Truck의 공포로 트럭에 전달되는 특성입니다. 또는 차량의 특수한 형태.


믹스 인은 좋은 아이디어라고 생각 될 것 같은 또 다른 문제가 있습니다. 치다 :

module A
  HELLO = "hi"
  def sayhi
    puts HELLO
  end
end

module B
  HELLO = "you stink"
  def sayhi
    puts HELLO
  end
end

class C
  include A
  include B
end

c = C.new
c.sayhi

어느 쪽이 이길까요? 루비에서는 후자 module B를 포함합니다 module A. 이제이 문제를 피하는 것이 소유. 모든 module Amodule B상수와 메소드가 네임 스페이스에 없을 가능성이 있는지 확인하십시오 . 충돌이 충돌 할 때 컴파일러가 전혀 경고하지 않습니다.

나는이 행동이 프로그래머 팀으로 확장되지 않는다고 주장한다. 구현하는 사람 class C이 범위 내의 모든 이름을 알고 가정 범위 안된다 . 루비는 심지어 다른 타입 의 상수 나 메소드를 재정의 할 수도 있습니다 . 있는 확실 나는 수하지 않다 어느 올바른 행동으로 간주 될 수있다.


내 생각 : 모듈은 행동을 공유하기위한 클래스는 클래스 관계를 모델링하기위한 것입니다. 기술적으로는 모든 것을 객체의 인스턴스로 만들고 원하는 동작 집합을 만들고 자하는 모듈에 혼합 할 수 있습니다. 그러나 그것은 형편없고, 무의미하며 읽기 어려운 디자인 일 것입니다.


귀하의 질문에 대한 답변은 대부분 상황에 따라. pubb의 관찰을 증류하여 선택은 주로 고려중인 도메인에 의해 결정됩니다.

그리고 예, ActiveRecord는 하위 클래스에 의해 확장되지 않고 있어야합니다. 또 다른 ORM ( datamapper)이 정확하게 달성합니다!


나는 Andy Gaskell의 대답을 매우 좋아합니다. 예, ActiveRecord는 상속을 사용하는 안이며 모델 / 클래스에 동작 (대부분 지속성)을 추가하는 모듈을 포함해야합니다. ActiveRecord는 잘못된 패러다임을 사용하고 있습니다.

같은 M 저는 MongoMapper보다 MongoId를 매우 좋아합니다. 왜냐하면 개발자가 문제 영역에서 의미있는 것을 모델링하는 방법으로 상속을 사용할 수있는 기회를 남기기 때문입니다.

Rails 커뮤니티의 어느 누구도 행동을 추가하는 것이 아니라 클래스 계층을 정의하는 데 사용되는 방식으로 "Ruby 상속"을 사용하지 않는 것이 슬프다.


믹스 인을 이해하는 가장 좋은 방법은 가상 수업입니다. 믹스 인은 클래스 또는 모듈의 상위 체인에 삽입 된 "가상 클래스"입니다.

"포함"을 사용하고 모듈을 전달하면 상속되는 클래스 바로 앞에 모듈을 조상 체인에 추가합니다.

class Parent
end 

module M
end

class Child < Parent
  include M
end

Child.ancestors
 => [Child, M, Parent, Object ...

Ruby의 모든 수업에는 싱글 톤 클래스도 있습니다. 이 싱글 톤 클래스에 추가 된 메서드는 개체에서 직접 호출 할 수 있으므로 "클래스"메서드로 작동합니다. 객체에 "extend"를 사용하고 객체 클래스에 모듈을 전달하면 모듈에서 클래스를 전달합니다.

module M
  def m
    puts 'm'
  end
end

class Test
end

Test.extend M
Test.m

singleton_class 메소드를 사용하여 싱글 톤 클래스에 액세스 할 수 있습니다.

Test.singleton_class.ancestors
 => [#<Class:Test>, M, #<Class:Object>, ...

Ruby는 모듈이 클래스 / 모듈로 혼합 될 때 모듈에 대한 후크를 제공합니다. included루비에서 제공하는 후크 메소드로 모듈이나 클래스에 모듈을 포함 할 때마다 호출됩니다. 포함 된 내용 extended확장을위한 관련 내용이 있습니다. 모듈이 다른 모듈이나 클래스에 의해 확장 될 때 호출됩니다.

module M
  def self.included(target)
    puts "included into #{target}"
  end

  def self.extended(target)
    puts "extended into #{target}"
  end
end

class MyClass
  include M
end

class MyClass2
  extend M
end

이 개발자가 사용할 수있는 흥미로운 패턴을 만듭니다.

module M
  def self.included(target)
    target.send(:include, InstanceMethods)
    target.extend ClassMethods
    target.class_eval do
      a_class_method
    end
  end

  module InstanceMethods
    def an_instance_method
    end
  end

  module ClassMethods
    def a_class_method
      puts "a_class_method called"
    end
  end
end

class MyClass
  include M
  # a_class_method called
end

보시다시피,이 단일 모듈 메서드를 추가하고 대상 클래스에서 직접 작동합니다 (이 경우 a_class_method () 호출).

ActiveSupport :: 관심사는 패턴을 캡슐화합니다. 다음은 ActiveSupport :: Concern을 사용하여 다시 동일한 모듈입니다.

module M
  extend ActiveSupport::Concern

  included do
    a_class_method
  end

  def an_instance_method
  end

  module ClassMethods
    def a_class_method
      puts "a_class_method called"
    end
  end
end

지금은 template 디자인 패턴 에 대해 생각하고 있습니다. 모듈은 옳지 않은 느낌이들 것입니다.

참고 URL : https://stackoverflow.com/questions/1282864/ruby-inheritance-vs-mixins

반응형