루비 상속 대 믹스인
루비에서는 여러 개의 믹스인을 포함할 수 있지만 하나의 클래스만 확장할 수 있기 때문에 상속보다는 믹스인을 선호할 것으로 보입니다.
제 질문: 만약 당신이 확장/포함되어야 하는 코드를 작성하고 있다면, 왜 그것을 클래스로 만들겠습니까?아니면 다른 방법으로, 왜 항상 모듈로 만들지 않습니까?
당신이 수업을 원하는 이유는 단 한 가지, 그것은 당신이 수업을 인스턴스화해야 하는 이유입니다.ActiveRecord의 경우::그러나 베이스는 직접 인스턴스화하지 않습니다.그래서 그것은 대신 모듈이 되어야 하지 않았나요?
저는 방금 The Well-Grounded Rubyist (참고로 훌륭한 책)에서 이 주제에 대해 읽었습니다.저자는 저보다 설명을 더 잘하기 때문에 그의 말을 인용하겠습니다.
단일 규칙이나 공식이 항상 올바른 설계를 가져오지는 않습니다.그러나 클래스 대 모듈 결정을 내릴 때는 몇 가지 고려 사항을 염두에 두는 것이 유용합니다.
모듈에 인스턴스가 없습니다.따라서 엔티티 또는 사물은 일반적으로 클래스에서 가장 잘 모델링되고, 엔티티 또는 사물의 특성 또는 특성은 모듈에 가장 잘 캡슐화됩니다.이에 따라 섹션 4.1.1에서 언급한 바와 같이 클래스 이름은 명사인 반면 모듈 이름은 종종 형용사(스택 대 스택 유사)입니다.
클래스는 하나의 슈퍼 클래스만 가질 수 있지만 원하는 만큼의 모듈을 혼합할 수 있습니다.상속을 사용하는 경우 합리적인 슈퍼클래스/하위클래스 관계를 만드는 것에 우선순위를 둡니다.클래스의 유일한 슈퍼 클래스 관계를 사용하여 클래스에 몇 가지 특성 중 하나로 판명될 수 있는 것을 부여하지 마십시오.
이러한 규칙을 한 예로 요약하면 다음과 같습니다.
module Vehicle
...
class SelfPropelling
...
class Truck < SelfPropelling
include Vehicle
...
대신 다음을 수행해야 합니다.
module SelfPropelling
...
class Vehicle
include SelfPropelling
...
class Truck < Vehicle
...
두 번째 버전은 엔티티와 속성을 훨씬 더 깔끔하게 모델링합니다.트럭은 차량에서 파생되는 반면, 셀프 추진은 차량의 특성(적어도 이 세계의 모델에서 우리가 관심을 갖는 모든 특성)입니다. 트럭은 차량의 후손 또는 특수한 형태이기 때문에 트럭에 전달되는 특성입니다.
믹스인은 좋은 아이디어라고 생각합니다. 하지만 여기에는 아무도 언급하지 않은 또 다른 문제가 있습니다. 네임스페이스 충돌입니다.고려 사항:
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 A
그리고.module B
의 상수 및 메서드가 있을 수 없는 이름 공간에 있습니다.문제는 컴파일러가 충돌이 발생할 때 경고를 전혀 하지 않는다는 것입니다.
는 이 의 큰 은 아니라고 합니다. -- 은 ▁implement▁person▁of▁i▁the▁thatmers다▁does▁teams▁shouldn저--▁you는주를 실행하는 사람이라고 안 됩니다. 당신은 실행하는 사람이라고 가정해서는 안 됩니다.class C
범위 내의 모든 이름에 대해 알고 있습니다.Ruby를 사용하면 다른 유형의 상수나 메서드를 재정의할 수도 있습니다.저는 그것이 올바른 행동으로 여겨질 수 있는지 확신할 수 없습니다.
제 생각에는 모듈은 행동을 공유하기 위한 것이고 클래스는 객체 간의 관계를 모델링하기 위한 것입니다.기술적으로 모든 것을 Object의 인스턴스로 만들고 원하는 동작 집합을 원하는 모듈에 혼합할 수 있지만, 이는 불량하고 위험하며 읽기 어려운 설계입니다.
당신의 질문에 대한 대답은 대체로 맥락에 따라 다릅니다.pubb의 관찰을 증류하면서, 선택은 주로 고려 중인 도메인에 의해 주도됩니다.
그리고 예, ActiveRecord는 하위 클래스에 의해 확장되는 것이 아니라 포함되어야 합니다.또 다른 ORM인 데이터 맵러는 이를 정확하게 달성합니다!
저는 Andy Gaskell의 답변을 매우 좋아합니다. 다만 ActiveRecord는 상속을 사용하지 않고 모델/클래스에 동작(대부분 지속성)을 추가하는 모듈을 포함해야 합니다.ActiveRecord는 단순히 잘못된 패러다임을 사용하고 있습니다.
같은 이유로, 저는 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 메서드를 사용하여 singleton 클래스에 액세스할 수 있습니다.
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby는 클래스/모듈에 혼합될 때 모듈에 대한 일부 후크를 제공합니다. included
Ruby에서 제공하는 후크 방식으로, 모듈을 일부 모듈 또는 클래스에 포함할 때마다 호출됩니다.포함된 것처럼, 연관된 것이 있습니다.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
보시다시피 이 단일 모듈은 인스턴스 메서드, "class" 메서드를 추가하고 대상 클래스에 직접 작용합니다(이 경우 a_class_method() 호출).
활성 지원:문제는 이 패턴을 캡슐화합니다.다음은 ActiveSupport를 사용하기 위해 다시 작성된 동일한 모듈입니다.우려 사항:
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
'sourcecode' 카테고리의 다른 글
루비 앰퍼샌드 콜론 바로가기 (0) | 2023.06.02 |
---|---|
하나의 양식에 두 개의 제출 단추 (0) | 2023.06.02 |
루비의 해시 값을 기준으로 해시 배열 내에서 검색하려면 어떻게 해야 합니까? (0) | 2023.05.28 |
Swift에서 한 뷰 컨트롤러의 방향을 세로 모드로만 잠그는 방법 (0) | 2023.05.28 |
탭 표시줄 탭 보기로 프로그래밍 방식으로 전환하시겠습니까? (0) | 2023.05.28 |