IT

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

lottoking 2020. 6. 28. 18:02
반응형

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


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

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

The advantages are the same as those for modules: encapsulation, grouping code used in only one place, and placing code closer to where it is used. A large project might have one outer module that occurs over and over in each source file and contains a lot of class definitions. When the various frameworks and library codes all do this, then they contribute only one name each to the top level, reducing the chance of conflicts. Prosaic, to be sure, but that's why they are used.

Using a class instead of a module to define the outer namespace might make sense in a one-file program or script, or if you already use the top level class for something, or if you are actually going to add code to link the classes together in true inner-class style. Ruby doesn't have inner classes but nothing stops you from creating about the same behavior in code. Referencing the outer objects from the inner ones will still require dotting in from the instance of the outer object but nesting the classes will suggest that this is what you might be doing. A carefully modularized program might always create the enclosing classes first, and they might reasonably be decomposed with nested or inner classes. You can't call new on a module.

You can use the general pattern even for scripts, where the namespace isn't terribly needed, just for fun and practice...

#!/usr/bin/env ruby

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

  def run
    ...
  end

  self
end.new.run

You probably want to use this to group your classes into a module. Sort of a namespace thing.

for example the Twitter gem uses namespaces to achieve this:

Twitter::Client.new

Twitter::Search.new

So both Client and Search classes live under the Twitter module.

If you want to check the sources, the code for both classes can be found here and here.

Hope this helps!


There is yet another difference between nested classes and nested modules in Ruby prior to 2.5 that other answers failed to cover that I feel must be mentioned here. It is the lookup process.

In short: due to top level constant lookup in Ruby prior to 2.5, Ruby may end up looking for your nested class in the wrong place (in Object in particular) if you use nested classes.

In Ruby prior to 2.5:
Nested class structure: Suppose you have a class X, with nested class Y, or X::Y. And then you have a top level class named also Y. If X::Y is not loaded, then following happens when you call X::Y:

Having not found Y in X, Ruby will try to look it up in ancestors of X. Since X is a class and not a module, it has ancestors, among which are [Object, Kernel, BasicObject]. So, it tries to look for Y in Object, where it finds it successfully.

Yet it is the top level Y and not X::Y. You will get this warning:

warning: toplevel constant Y referenced by X::Y


Nested module structure: Suppose in the previous example X is a module and not a class.

A module only has itself as ancestor: X.ancestors would produce [X].

In this case, Ruby won't be able to look for Y in one of ancestors of X and will throw a NameError. Rails (or any other framework with autoloading) will try to load X::Y after that.

See this article for more information: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/

In Ruby 2.5:
Top level constant lookup removed.
You may use nested classes without fear of encountering this bug.


In the addition to previous answers: Module in Ruby is a class

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

참고URL : https://stackoverflow.com/questions/6195661/when-to-use-nested-classes-and-classes-nested-in-modules

반응형