我是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进行编码时,我会对这种情况下的最佳实践提供一些指导。
答案 0 :(得分:6)
由于动态类型,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