Ruby抽象

时间:2009-12-22 05:45:32

标签: ruby oop ftp sftp abstraction

我是Ruby的新手,主要来自C#和ActionScript 3(以及其他语言)。我很好奇抽象功能。具体来说,包装和抽象Ruby的FTP和SFTP库。

我在四处寻找并发现了一颗名为Backup的宝石。它确实引起了我的注意,因为它支持通过S3,SCP,SFTP和FTP备份内容。所以我想,“哇,这是一个完美的例子!”我开始浏览源代码,但之后我遇到了类似的代码:

case backup.procedure.storage_name.to_sym
  when :s3    then records = Backup::Record::S3.all   :conditions => {:trigger => trigger}
  when :scp   then records = Backup::Record::SCP.all  :conditions => {:trigger => trigger}
  when :ftp   then records = Backup::Record::FTP.all  :conditions => {:trigger => trigger}
  when :sftp  then records = Backup::Record::SFTP.all :conditions => {:trigger => trigger}
end

view the full source on GitHub

它充斥着case / when语句!如果我在C#中攻击它,我会写一个Protocol接口(或抽象类),让FTP和SFTP实现它。然后我的客户端类只会传递一个Protocol实例而不关心实现。零开关/箱。

在使用Ruby进行编码时,我会对这种情况下的最佳实践提供一些指导。

5 个答案:

答案 0 :(得分:6)

你也可以在Ruby中这样做

由于动态类型,Ruby不需要接口。就此而言,它不需要原型,签名或模板,甚至子类,虽然存在,但并非绝对必要。

当我说“不需要”时,我只是说你所指的设计模式可以直接在Ruby中实现。因为在“编译时”没有强制执行调用限制,所以任何依赖于接口或任何多边形风格的设计模式都可以直接在Ruby中使用。

是的,看起来好像该软件包没有充分利用可能的抽象,但也许(a)无关紧要,只要它有效。毕竟,你不需要输入它,或者(b)使用的简单组合模式有一些不那么明显的好处。

答案 1 :(得分:2)

我认为有几种方法可以优雅地完成它。一,是使用上面提到的TK作为传感器。另一种方法是使用“method_missing”,这是Ruby在无法找到现有方法时调用的方法。

Metaprogramming Ruby对这两个选项都有很好的报道。幸运的是,这是在线免费样本章节(如果你想了解更多,我推荐这本书。)

抱歉没有为您提供代码段,但请仔细阅读并查看是否有帮助。

答案 2 :(得分:1)

大多数情况下,OO语言中的案例表达式表明您没有正确使用多态。在这种情况下,我会这样做:

backup.procedure.storage_class.all :conditions => {:trigger => trigger}

storage_class返回适当的类。 (实际上,我更愿意将storage_class作为备份本身的属性,但我不知道这是否适用于此库的设计。)

答案 3 :(得分:0)

公平地说,上面的代码是非常明确的。除了将它作为对象的层次结构实现之外,你可以坚持做一些像

这样的事情
storage_method = backup.procedure.storage_name.upcase

records = eval("Backup::Record::#{storage_method}.all :conditions => {:trigger => trigger}"

我并不是说这实际上是正确的,但希望它说明了我的观点,即简洁的代码并不总是比显式代码更好。 Ruby可能和C一样危险: - )

答案 4 :(得分:0)

可能有更好的方法,但这是我的镜头。

ALLOWD_OPTIONS = [:s3, :scp, :ftp ,:sftp].freeze
type = ALLOWD_OPTIONS.detect { |e| e == backup.procedure.storage_name.to_sym }
if type
  records = send(%s"Backup::Record::#{type.upcase}.all", :conditions => {:trigger => trigger})
end

if [:s3, :scp, :ftp, :sftp].include?(backup.procedure.storage_name.to_sym)
   records = __send__ (%s"Backup::Record::#{backup.procedure.storage_name.to_sym.upcase}.all", 
                       :conditions => {:trigger => trigger})
end

如果您使用的是Ruby 1.9,则可以使用public_send()来获得额外的安全性。我查看了有问题的文件。有很多案例陈述。您可以使用私有方法执行上面写的操作,以最大限度地减少重复。

ALLOWD_OPTIONS = [:s3, :scp, :ftp ,:sftp].freeze

records = send_method_with_type("all", backup.procedure.storage_name.to_sym, 
                                       :conditions => {:trigger => trigger})

private

def send_method_with_type(method, type, *args)
  raise unless ALLOWD_OPTIONS.inlucde? type
  send(%s"Backup::Record#{type.upcase}.#{method}", args)
end