2017-09-15 74 views
-1

我有一个关于如何在运行时包含模块和执行方法的问题。我阅读了元编程,我想我已经有了基本观点,但我不明白如何在我的具体情况下使用它。Ruby和元编程和模块

例如: 我想基于块文本两种不同的方式

class TextGenerator 

def create_text 
if condition 
    create_full_text 
else 
    create_short_text 
end 
end 

private 

def create_full_text 
intro 
middle 
ending 
end 

def create_short_text 
middle 
end 

def intro 
"intro" 
end 

def middle 
"middle" 
end 

def ending 
"ending" 
end 

end 

我想什么来实现的,我想提取方法的功能create_full_textcreate_short_text到专用模块,如果条件匹配,则包括模块。文本创建将通过调用create_text从包含的模块中发生。

我的问题是可以理解的,也使这个想法有意义吗? 也许有人会把我推向正确的方向。


根据Sergios的回答,还有一种动态扩展方法。

相反的:

if condition 
generator.extend(WithFullText) 
else 
generator.extend(WithShortText) 
end 

这将是巨大的,有像(非常基本的广泛为例):

@MODULES = { 
full: "WithFullText", 
short: "WithShortText" 
} 

def create_text_by_type(type) 
module_name = @MODULES[type] 
#no idea how this can work 
module_class = getModuleByName(module_name) 
generator.extend(module_class) 
generator.create_text 
end 

最佳亚历

+1

虽然技术上可行,但动态运行时实例修补很少是一个好主意。你想达到目的吗?或者这只是一次抛弃练习? –

+0

这个编辑就是我所说的“它应该作为另一个问题”。我把你推向了正确的方向,对吧?所以原来的问题得到了回答。像这样的突变问题是不鼓励的。 –

回答

0

也许有人可以推动我正确的方向

当然。例如,您可以使用extend从模块动态添加方法。

module WithFullText 
    def create_full_text 
    "full text" 
    end 
end 

class TextGenerator 
end 

generator = TextGenerator.new 
generator.create_full_text # ~> -:5:in `<main>': undefined method `create_full_text' for #<TextGenerator:0x007ffb818b1990> (NoMethodError) 
generator.extend(WithFullText) 
generator.create_full_text # => "full text" 

虽然通常情况下,人们只是包括方法,然后调用其中之一。

class TextGenerator 
    include MyTextMethods 
end 

你需要一个很好的理由做到这一点(因为这意味着更复杂的代码/流量)。

+0

谢谢塞尔吉奥, 这看起来像,它可以为我工作。实际上,会有越来越多的模块,它们将以自己的方式创建文本,我不希望包含所有可用的模块。我还在 –

+0

@AlexBug后面添加了一个跟进:但为什么不包含所有可用的模块? –

+0

“@SergioTulentsev”是不是类重载添加x金额模块,而不是只有一个,这是需要的 –

0

我相信你在这里需要的是策略设计模式。有比使用include更好的实现方法。元编程也是一个强大的工具,但通过使用简单的case而不是一些正在使用的神奇方法生成或使用send方法,代码很多时候更易读易懂。 怎么是这样的:

module TextGenerator 
    class FullText 
    def self.generate 
     "full text" 
    end 
    end 

    class ShortText 
    def self.generate 
     "short text" 
    end 
    end 
end 


module ChooseTextGeneratorStrategy 
    def self.included klass 
    klass.singleton_class.send(:attr_reader, :create_text_type) 
    end 

    def create_text 
    case self.class.create_text_type 
    when :short 
     TextGenerator::ShortText.generate 
    when :full 
     TextGenerator::FullText.generate 
    end 
    end 
end 


class ClassNeedsFullText 
    include ChooseTextGeneratorStrategy 
    @create_text_type = :full 
end 

class ClassNeedsShortText 
    include ChooseTextGeneratorStrategy 
    @create_text_type = :short 
end 

p ClassNeedsFullText.new.create_text # "full text" 
p ClassNeedsShortText.new.create_text # "short text" 

的命名是也许不是最好的,但你可以得到点。如果您需要ClassNeedsFullText的上下文,则可以通过参数简单传递它:TextGenerator::FullText.generate self@create_text_type只是一个例子。您可以通过使用帮助程序更加简化它:

def act_like_create_text type 
    include ChooseTextGeneratorStrategy 

    @create_text_type = type 
end 

class ClassNeedsShortText 
    act_like_create_text :short 
end 

p ClassNeedsShortText.new.create_text # "short text" 
+0

这个。适当的面向对象是这里走的路。 (如果我正确理解他们的问题)。策略和专注的单一目的课程。 –

+0

虽然你的实现过于复杂。您不需要任何类级别的逻辑,因为该策略在实例级别解决。也许就像[this]一样简单(https://pastebin.com/7axUVJYd)? –

+0

是的,我知道,这是为了展示什么是可能的。另一方面,如果只有一行“act_like_create_text:short”,那么他们有很多课程; - )剩下的就取决于他们在战略之间如何选择。 –