Java에서 'Private Static Final'및 'Public Static Final'클래스 변수의 가장 가까운 루비 표현?

StackOverflow https://stackoverflow.com/questions/2441524

문제

아래의 Java 코드가 주어지면이 두 가지를 대표 할 수있는 가장 가까운 것은 무엇입니까? static final 루비 클래스의 변수? 그리고 루비에서 private static 그리고 public static 자바에있는 변수?

public class DeviceController
{
  ...
  private static final Device myPrivateDevice = Device.getDevice("mydevice");
  public static final Device myPublicDevice = Device.getDevice("mydevice");
  ...
  public static void main(String args[])
  {
   ...
  }
}
도움이 되었습니까?

해결책

루비에는 실제로 동등한 구조가 없습니다.

그러나 그것은 당신이 고전적인 포팅 실수 중 하나를 만드는 것처럼 보입니다. 당신은 다음과 같습니다. 해결책 언어 A에서는 언어 B로 번역하려고 노력하십시오. 실제로해야 할 일은 문제 그런 다음 언어 B로 해결하는 방법을 알아 봅니다.

나는 당신이 그 작은 코드에서 해결하려고하는 것이 무엇인지 정말로 확신 할 수 없지만 여기에 있습니다. 하나 루비에서 구현하는 방법에 대한 가능한 아이디어 :

class DeviceController
  class << self
    def my_public_device;  @my_public_device  ||= Device['mydevice'] end

    private

    def my_private_device; @my_private_device ||= Device['mydevice'] end
  end
end

또 다른 것이 있습니다 :

class DeviceController
  @my_public_device  ||= Device['mydevice']
  @my_private_device ||= Device['mydevice']

  class << self
    attr_reader :my_public_device, :my_private_device
    private :my_private_device
  end
end

(차이점은 첫 번째 예제가 게으르다는 것입니다. 해당 속성 판독기가 먼저 호출 될 때만 인스턴스 변수 만 초기화됩니다. 두 번째는 클래스 본체가 실행 되 자마자, 필요하지 않더라도, 그와 같이 클래스 본체가 실행 되 자마자 초기화됩니다. Java 버전이 있습니다.)

여기에 몇 가지 개념을 살펴 보겠습니다.

Ruby에서는 다른 모든 "적절한"( "적절한"의 다양한 정의에 대한)와 마찬가지로 객체 지향 언어, 상태 (인스턴스 변수, 필드, 속성, 슬롯, 속성, 호출하려는 모든 것) 언제나 사적인. 거기 있습니다 절대 안돼 외부에서 액세스하기 위해. 객체와 통신하는 유일한 방법은 메시지를 보내는 것입니다.

참고 : "No Way", "Always", "유일한 방법"등을 쓸 때마다 실제로는 "반사를 제외하고는 방법이 없다"는 의미는 없습니다. 이 특별한 경우에는 있습니다 Object#instance_variable_set, 예를 들어.

다시 말해, 루비에서 변수는 항상 비공개이며, 이들에 액세스 할 수있는 유일한 방법은 getter 및/또는 setter 방법을 통한 것입니다.

이제 나는 계속 글을 쓰고 있습니다 인스턴스 변수, 그러나 Java 예에서는 우리가 가지고 있습니다 정적 필드, 즉 수업 변수. 루비에서는 자바와 달리 수업도 대상입니다. 그들은의 사례입니다 Class 클래스와 다른 객체와 마찬가지로 인스턴스 변수를 가질 수 있습니다. 따라서 Ruby에서 클래스 변수와 동등한 것은 실제로 클래스 인 객체에 속하는 표준 인스턴스 변수 일뿐입니다.

(클래스 계층 변수도 있습니다. @@sigil. 그것들은 정말 이상합니다. 아마도 당신은 아마 그들을 무시해야 할 것입니다. 클래스 계층 변수는 전체 클래스 계층, 즉 클래스, 즉 모든 서브 클래스 및 하위 클래스 및 하위 클래스 및 모든 클래스의 모든 인스턴스에 걸쳐 공유됩니다. 실제로, 그것들은 클래스 변수보다 글로벌 변수와 비슷합니다. 그들은 실제로 부름을 받아야합니다 $$var 대신에 @@var, 인스턴스 변수보다 글로벌 변수와 훨씬 더 밀접한 관련이 있기 때문입니다. 그들은 완전히 쓸모가 없지만 거의 유용하지 않습니다.)

따라서 "필드"부분 (Java Field == Ruby 인스턴스 변수)을 다루었 고, "공개"및 "개인"부품을 다루었습니다 (Ruby에서는 인스턴스 변수가 항상 개인입니다. 공개 getter/setter 방법을 사용하고 "정적"부분 (Java static field == Ruby 클래스 인스턴스 변수)을 다루었습니다. "최종"부분은 어떻습니까?

Java에서 "Final"은 "Const"철자의 재미있는 방법입니다. const C 및 C ++와 같은 언어의 키워드는 미묘하게 깨졌으며 사람들을 혼동하고 싶지 않았습니다. 루비 하다 상수가 있습니다 (대문자로 시작하여 표시). 불행히도, 그들은 경고를 생성하면서 수정하려고 시도하는 것이 실제로 작동하기 때문에 실제로 일정하지 않습니다. 따라서 컴파일러 강화 규칙보다 더 많은 규칙입니다. 그러나 상수의 더 중요한 제한은 항상 공개된다는 것입니다.

따라서 상수는 거의 완벽합니다. 수정할 수 없습니다 (음, 그들은 그렇지 않아야합니다 수정), 즉, 그들은 그렇습니다 final, 그들은 클래스 (또는 모듈)에 속합니다. static. 그러나 그들은 항상입니다 public, 불행히도 그들은 모델링하는 데 사용될 수 없습니다 private static final 필드.

그리고 이것이 솔루션 대신 문제에 대한 생각이 들어오는 시점입니다. 원하는 것은 무엇입니까? 당신은 그 말을 원합니다

  1. 수업에 속하며
  2. 쓰여지지 않으면 읽을 수 있습니다.
  3. 한 번만 초기화됩니다
  4. 개인 또는 공개 일 수 있습니다.

당신은 그 모든 것을 달성 할 수 있지만 Java와는 완전히 다른 방식으로 다음과 같습니다.

  1. 클래스 인스턴스 변수
  2. 세터 방법을 제공하지 말고 getter 만 제공하십시오
  3. 루비를 사용하십시오 ||= 한 번만 할당하는 복합 할당
  4. getter 방법

당신이 걱정해야 할 유일한 것은 당신이 할당하지 않는 것입니다 @my_public_device 어느 곳에서나 또는 더 나은 아직도 전혀 액세스하지 마십시오. 항상 getter 방법을 사용하십시오.

예, 이건 ~이다 구현의 구멍. 루비는 종종 "성인의 언어"또는 "동의 성인 언어"라고 불립니다. 즉, 컴파일러가 특정 사항을 시행하는 대신 문서에 넣고 동료 개발자가 다른 사람을 만지는 것을 배웠다는 것을 신뢰합니다. 사람들의 개인은 무례합니다 ...


완전히 다른 개인 정보에 대한 접근 방식은 기능적 언어로 사용되는 것입니다 : 클로저 사용. 클로저는 어휘 환경이 범위를 벗어난 후에도 어휘 환경에 가까운 코드 블록입니다. 개인 상태를 구현하는이 방법은 제도에서 매우 인기가 있지만 최근 Douglas Crockford et al. JavaScript의 경우. 루비의 예는 다음과 같습니다.

class DeviceController
  class << self
    my_public_device, my_private_device = Device['mydevice'], Device['mydevice']

    define_method :my_public_device  do my_public_device  end
    define_method :my_private_device do my_private_device end

    private :my_private_device
  end # <- here the variables fall out of scope and can never be accessed again
end

내 대답의 맨 위에있는 버전에 미묘하지만 중요한 차이점에 주목하십시오. @ 시길. 여기서 우리는 창조하고 있습니다 현지의 변수는 아닙니다 사례 변수. 클래스 본문이 끝나 자마자 해당 로컬 변수는 범위에서 벗어나 다시는 액세스 할 수 없습니다. 두 개의 getter 방법을 정의하는 두 블록은 클래스 본체에 닫히기 때문에 여전히 액세스 할 수 있습니다. 이제 그들은입니다 진짜 사적인 그리고 그들은 final, 전체 프로그램에서 여전히 액세스 할 수있는 유일한 것은 순수하기 때문입니다. 얻는 사람 방법.

이것은 아마도 관용 루비가 아니지만 LISP 또는 JavaScript 배경을 가진 사람에게는 충분히 명확해야합니다. 또한 매우 우아합니다.

다른 팁

최종 변수에 대해 가장 가까운 것은 문제의 변수를 모듈의 인스턴스 변수로 넣는 것입니다.

class Device
    # Some static method to obtain the device
    def self.get_device(dev_name)
        # Need to return something that is always the same for the same argument
        dev_name
    end
end

module FinalDevice
    def get_device
        # Store the device as an instance variable of this module...
        # The instance variable is not directly available to a class that
        # includes this module.
        @fin ||= Device.get_device(:my_device).freeze
    end
end

class Foo
    include FinalDevice
    def initialize
        # Creating an instance variable here to demonstrate that an
        # instance of Foo cannot see the instance variable in FinalDevice,
        # but it can still see its own instance variables (of course).
        @my_instance_var = 1
    end
end

p Foo.new

p (Foo.new.get_device == Foo.new.get_device)

이 출력 :

#<Foo:0xb78a74f8 @my_instance_var=1>
true

여기서는 장치를 모듈로 캡슐화하면 해당 모듈을 통해서만 장치에 액세스 할 수 있다는 것입니다. 수업에서 Foo, 수정 방법이 없습니다 어느 직접 행동하지 않고 액세스하는 장치 Device 클래스 또는 FinalDevice 기준 치수. 그만큼 freeze 전화로 FinalDevice 귀하의 요구에 따라 적절하거나 적절하지 않을 수 있습니다.

공공 및 개인 액세서를 만들고 싶다면 수정할 수 있습니다. Foo 이와 같이:

class Foo
    include FinalDevice

    def initialize
        @my_instance_var = 1
    end

    def get_device_public
        get_device
    end

    private
    def get_device_private
        get_device
    end

    private :get_device
end

이 경우 수정해야 할 것입니다 FinalDevice::get_device 논쟁도 취합니다.

업데이트 : @Banister가 그것을 지적했습니다 @fin 선언 된대로 FinalDevice 실제로 인스턴스에 의해 액세스 할 수 있습니다 Foo. 기본 텍스트 출력이 아니기 때문에 Foo#inspect, 내부는 아니었다 Foo.

더 명시 적으로 만들어서 이것을 치료할 수 있습니다 @fin 인스턴스 변수 FinalDevice 기준 치수:

class Device
    def self.get_device(dev_name)
        dev_name
    end
end

module FinalDevice
    def get_device
        FinalDevice::_get_device
    end

    protected
    def self._get_device
        @fin ||= Device.get_device(:my_device).freeze
    end
end

class Foo
    include FinalDevice

    def get_device_public
        get_device
    end

    def change_fin
        @fin = 6
        @@fin = 8
    end

    private
    def get_device_private
        get_device
    end

    private :get_device
end

f = Foo.new
x = f.get_device_public
f.change_fin
puts("fin was #{x}, now it is #{f.get_device_public}")

올바르게 출력 :

fin was my_device, now it is my_device
class DeviceController
  MY_DEVICE = Device.get_device("mydevice")
end

그리고 그래, require 'device' 필요한 경우.

경고를 제외하고는 다른 곳에서 상수를 재정의하는 것을 막을 수는 없습니다. :)

루비의 개인 정적 :

class DeviceController
    @@my_device = Device.get_device("mydevice")
end

루비의 공공 정적 :

class DeviceController       
    def self.my_device; @@my_device; end

    @@my_device = Device.get_device("mydevice")
end

루비는 '최종'을 가질 수 없습니다 :)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top