[ruby] 모듈에 중첩 된 클래스와 중첩 클래스를 사용하는시기

서브 클래스와 모듈을 사용하는시기에 대해 잘 알고 있지만 최근에는 다음과 같이 중첩 된 클래스를보고 있습니다.

class Foo
  class Bar
    # do some useful things
  end
end

모듈에 중첩 된 클래스뿐만 아니라 다음과 같습니다.

module Baz
  class Quux
    # more code
  end
end

문서와 기사가 희소하거나 올바른 검색어를 찾을만큼 주제에 대해 교육을받지 못했지만 주제에 대한 많은 정보를 찾을 수 없습니다.

누군가가 그 기술이 왜 언제 사용되는지에 대한 게시물에 대한 예나 링크를 제공 할 수 있습니까?



답변

다른 OOP 언어에는 내부 클래스 가 있으며 상위 클래스에 바인딩되지 않으면 인스턴스화 할 수 없습니다. 예를 들어 Java에서는

class Car {
    class Wheel { }
}

Car클래스의 메소드 만을 작성할 수 있습니다 Wheel.

루비에는 그런 행동이 없습니다.

루비에서

class Car
  class Wheel
  end
end

~와 다르다

class Car
end

class Wheel
end

단지 클래스의 이름으로 WheelCar::Wheel. 이러한 이름의 차이 Car::Wheel는 일반 휠과 달리 클래스가 자동차 휠만 나타낼 수 있다는 것을 프로그래머에게 명백하게 할 수 있습니다. 루비에서 중첩 클래스 정의는 선호의 문제이지만, 두 클래스 간의 계약을보다 강력하게 시행하고 클래스와 그 사용에 대한 자세한 정보를 전달한다는 의미에서 목적을 제공합니다.

그러나 루비 인터프리터에게는 이름의 차이 일뿐입니다.

두 번째 관찰에서 모듈 내부에 중첩 된 클래스는 일반적으로 클래스의 네임 스페이스에 사용됩니다. 예를 들어 :

module ActiveRecord
  class Base
  end
end

~와 다르다

module ActionMailer
  class Base
  end
end

이것이 모듈 내부에 중첩 된 클래스의 유일한 사용은 아니지만 일반적으로 가장 일반적입니다.


답변

Ruby에서 중첩 클래스를 정의하는 것은 모듈에서 클래스를 정의하는 것과 유사합니다. 실제로 클래스 간의 연관을 강요하지 않고 상수의 네임 스페이스를 만듭니다. (클래스 및 모듈 이름은 상수입니다.)

수락 된 답변이 아무것도 맞지 않았습니다. 1 아래 예에서는 기존 클래스를 포함하지 않고 어휘로 묶인 클래스의 인스턴스를 만듭니다.

class A; class B; end; end
A::B.new

캡슐화, 한 곳에서만 사용되는 코드 그룹화 및 사용되는 위치에 더 가까운 코드 배치와 같은 장점은 모듈과 동일합니다. 큰 프로젝트에는 각 소스 파일에서 반복적으로 발생하고 많은 클래스 정의가 포함 된 하나의 외부 모듈이있을 수 있습니다. 다양한 프레임 워크와 라이브러리 코드가 모두이 작업을 수행 할 때 각각 하나의 이름 만 최상위 레벨에 제공하여 충돌 가능성을 줄입니다. 확실히, 그러나 그것이 그들이 사용되는 이유입니다.

외부 네임 스페이스를 정의하기 위해 모듈 대신 클래스를 사용하는 것은 단일 파일 프로그램이나 스크립트에서 또는 이미 최상위 클래스를 사용하거나 클래스를 서로 연결하는 코드를 추가하려는 경우에 의미가 있습니다. 진정한 내부 클래스 스타일. 루비에는 내부 클래스가 없지만 코드에서 동일한 동작을 만드는 것을 막는 것은 없습니다. 내부 개체에서 외부 개체를 참조하려면 여전히 외부 개체의 인스턴스에서 도팅을 수행해야하지만 클래스를 중첩하면 이것이 현재 수행중인 작업 일 것입니다. 신중하게 모듈화 된 프로그램은 항상 둘러싸는 클래스를 먼저 만들고 중첩 또는 내부 클래스로 합리적으로 분해 될 수 있습니다. new모듈을 호출 할 수 없습니다 .

네임 스페이스가별로 필요하지 않은 스크립트에서도 재미와 연습을 위해 일반적인 패턴을 사용할 수 있습니다 …

#!/usr/bin/env ruby

class A
  class Realwork_A
    ...
  end
  class Realwork_B
    ...
  end

  def run
    ...
  end

  self
end.new.run


답변

이것을 사용 하여 클래스를 모듈로 그룹화 할 수 있습니다. 네임 스페이스의 종류.

예를 들어 Twitter gem 은 네임 스페이스를 사용하여이를 달성합니다.

Twitter::Client.new

Twitter::Search.new

따라서 클래스 ClientSearch클래스는 모두 Twitter모듈 아래에 있습니다.

소스를 확인하려면 두 클래스의 코드를 여기여기 에서 찾을 수 있습니다 .

도움이 되었기를 바랍니다!


답변

2.5 이전의 Ruby에서 중첩 클래스와 중첩 모듈 사이에는 또 다른 차이점이 있는데 여기에서 언급해야 할 다른 답변을 다루지 못했습니다. 조회 프로세스입니다.

간단히 말해서 : Ruby 2.5 이전의 최상위 상수 조회로 인해, 중첩 클래스를 사용하는 경우 Ruby는 중첩 된 클래스 ( Object특히)를 잘못 찾을 수 있습니다.

루비에서 전 2.5 :
중첩 클래스 구조 :
당신은 클래스가 있다고 가정 X중첩 클래스를, Y또는 X::Y. 그런 다음 이름이 top 인 최상위 클래스도 있습니다 Y. 경우 X::Y로드되어 있지 않은 경우, 다음은 호출 할 때 발생 X::Y:

찾을 수없는 데 Y에서 X, 루비의 조상에서 그것을 찾기 위해 노력할 것입니다 X. 이후X클래스가 아니라 모듈이며 조상이 있으며 그중에는 [Object, Kernel, BasicObject]. 그래서, 그것은을 찾기 위해 시도 Y에서 Object성공적를 발견하는 경우,.

그러나 그것은 최상위 수준 Y이며 그렇지 않습니다 X::Y. 이 경고가 나타납니다.

warning: toplevel constant Y referenced by X::Y

중첩 모듈 구조 :
이전 예제 X에서 클래스가 아니라 모듈 이라고 가정합니다 .

모듈 자체는 조상으로 만 X.ancestors사용 [X]됩니다.

이 경우 루비는 Y의 조상 중 하나 를 찾을 수 없으며를 X던질 것 NameError입니다. 레일 (또는 자동 로딩 기능이있는 다른 프레임 워크)은 X::Y그 후에 로드를 시도 합니다.

자세한 내용은이 기사를 참조하십시오 : https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/

In Ruby 2.5 :
최상위 상수 조회가 제거되었습니다.
이 버그가 발생할 염려없이 중첩 클래스를 사용할 수 있습니다.


답변

이전 답변 외에도 Ruby의 모듈은 클래스입니다.

$ irb
> module Some end
=> nil
> Some.class
=> Module
> Module.superclass
=> Object


답변