【问题标题】:How to allow initializing a class from a particular class in ruby and nowhere else?如何允许从 ruby​​ 中的特定类初始化一个类,而其他任何地方都没有?
【发布时间】:2020-09-28 10:02:29
【问题描述】:
module A
  module B
    class Foo
      def initialize(args)
        @args = args
      end
      def call
        puts 'Inside Foo'
      end
    end
  end
end

module C
  class Boo
    def initialize(args)
      @args = args
    end
    def call
      puts 'Inside Boo'
      A::B::Foo.new(@args).call
    end
  end
end

boo = C::Boo.new(nil).call
# Inside Boo
# Inside Foo

A::B::Foo.new(nil).call
# Inside Foo

如何避免 A::B::Foo.new(nil).call ? 它应该只能从 Boo 类访问。

如果有人想访问Foo 类,他们将能够从Boo 访问它。 我怎样才能做到这一点?

搜索了互联网,但找不到应该称之为这个概念的东西?

【问题讨论】:

  • 你可以将A::B::Foo.new设为private(并使用sendBoo中调用它)
  • 你为什么要这样做?
  • 我们在class Boo 中有一组验证,我无法在class Foo 中添加。所以,我不希望任何人在没有这些验证的情况下使用class Boo

标签: ruby-on-rails ruby class module


【解决方案1】:

这是 ruby​​ - 所以不存在将对象设为“私有”的铁定方法。 (例如,您可以通过.send! 访问私有方法!)但您至少可以定义一个私有接口

但是,从 OOP 的角度来看,您的界面实际上并没有多大意义。为什么A::B::Foo 只能在C::Boo 内访问? 如果A::B::Foo 是私有的,那么它应该只能在A::B 内访问,而不能在其他任何地方访问。

你要找的关键方法是:private_constant

您可以使用const_get 来规避私有常量查找异常。

因此,我们可以“破解”您当前的实现,使其按如下方式工作:

module A
  module B
    class Foo
      def initialize(args)
        @args = args
      end
      def call
        puts 'Inside Foo'
      end
    end
    private_constant :Foo
  end
end


module C
  class Boo
    def initialize(args)
      @args = args
    end
    def call
      puts 'Inside Boo'
      A::B.const_get(:Foo).new(@args).call
    end
  end
end

# This works:
C::Boo.new(nil).call

# This errors:
A::B::Foo.new(nil).call

【讨论】:

  • 同样,您可以通过将A::B::new 设为私有方法来实现上述目的。但是我建议使用private_constant,因为实际上在某些上下文中初始化这些对象似乎很好......我只是认为说“你只能在C中初始化它们”在架构上没有多大意义!
  • *A::B::Foo::new
  • 从您将 C 视为工厂的角度来看,这是有道理的,并且您不希望其他类能够创建 A::B,除非它们使用 C 的接口。例如,这在 C# 和 Java 等语言中使用“internal”关键字。 (有趣的故事,因为我来自 C# 背景,我不久前就问过这个问题,我的问题被标记为重复。人们完全没有抓住重点)
  • @cesartalves 啊,我以前没听说过这个... C# 中有一个InternalVisiblesTo 方法,很有趣!这也与 C++ 中的“朋友类”功能非常相似。
  • Ruby 并没有“朋友类”的概念。我确实找到了添加功能的this gem,虽然我还没有尝试过!
猜你喜欢
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 2018-02-15
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2021-03-23
相关资源
最近更新 更多