为了进行测试和管理,我正在寻找一个与API通信的类。我已经断开了连接和身份验证,但是正在为类的基本结构和大小苦苦挣扎。
我的主要目标是保持每个应用程序域分离,但仍然易于通过一个类/连接进行访问。我已经做了一个简单的例子来寻找我想要的东西。实际上,每个域都有自己的一套业务规则要遵循,这就是为什么我想将它们分开,而API连接保持不变的原因。
例如,在CLI级别,我要调用:
$ client_one = Api.new("one")
$ client_two = Api.new("two")
$ client_one.Bikes.delete(1)
> deleted bike 1 from one
$ client_two.Phones.new(phone)
> posted phone iPhone to two
我的想法是将模块嵌套在Api类中,但是我无法使其正常工作或找到正确的语法。
class Api
def initialize(client)
@client = client
@connection = Authentication.get_connection(@client)
end
#preferable put each submodule in a separate file
module Authentication
def get_connection(client)
#code to get Faraday connection
end
end
module Bikes
def new(object)
#code to post new bike
@connection.post(object)
puts "posted bike #{object.name} to #{@client}"
end
def delete(id)
#code to delete old bike
@connection.delete(id)
puts "deleted bike #{id} from #{@client}"
end
end
module Phones
def new(object)
#code to post new phone
@connection.post(object)
puts "posted phone #{object.name} to #{@client}"
end
end
end
这将导致以下错误:
NoMethodError: undefined method `Bikes' for #<Api:0x0000000003a543a0>
有可能实现我的目标,还是有更好的“ Ruby”方法来实现它?
此外,是否可以将子模块拆分为不同的文件?例如:
api.rb
modules
+ -- authentication.rb
+ -- bikes.rb
+ -- phones.rb
对于您的示例中的Ruby OOP是如何工作的,存在一些基本的误解,没有完整的代码示例,也没有机会向您询问您要完成的工作,很难指导您找到最合适的答案。我给出的任何答案都将部分基于经验,部分取决于意见,因此您可能还会看到其他答案。
从高层次上讲,您应该在模块中有类,而在类中则没有模块。尽管您可以将模块放在类中,但是在这样做之前最好更好地了解为什么要这样做。
接下来,您在其中定义的模块和方法不会自动变为父类的实例可访问的,因此client.Bikes
将永远无法工作,因为Ruby希望Bikes
在Api
该类中找到一个命名为实例的方法。它不会寻找具有该名称的模块。
访问已定义的模块和模块方法的唯一方法是在类/模块级别使用它们。因此,如果您有:
class Foo
module Bar
def baz
puts 'foobarbaz'
end
end
end
您可以在类/模块级别执行此操作:
Foo::Bar.baz
foobarbaz
=> nil
但是您不能在实例级别执行任何操作:
Foo.new::Bar.baz
TypeError: #<Foo:0x00007fa037d39260> is not a class/module
Foo.new.Bar.baz
NoMethodError: undefined method `Bar' for #<Foo:0x00007fa037162e28>
因此,如果到目前为止,您仍然了解示例结构为何不起作用,那么您可以进行一些更明智的构建。让我们从命名和类/模块结构开始。
首先,Api
这里的名称很烂,因为您通常会使用提供API而不连接到API的Api
东西,所以我建议您将该名称描述性更强,并使用一个模块来表示您正在封装一个或多个相关的类:
module MonthyApiClient
end
接下来,我建议添加一个Client
类来封装与实例化用于连接到API的客户端有关的所有内容:
module MonthyApiClient
class Client
def initialize
@client = nil # insert your logic here
@connection = nil # insert your logic here
end
end
end
client
与connection
您的代码示例之间的关系尚不清楚,因此为简单起见,我将假装它们可以组合为一个类(Client
),并且我们将Authentication
完全删除该模块。
接下来,我们需要整合一个合理的方式module Bikes
和module Phones
这个代码。将它们转换为类没有意义,因为不需要实例化它们。这些纯粹是辅助函数,可以为的实例执行某些操作Client
,因此它们应该是该类内的实例方法:
module MonthyApiClient
class Client
def initialize
# insert your logic here
@client = nil
@connection = nil
end
def create_bike
# insert your logic here
# e.g., @connection.post(something)
end
def delete_bike
# insert your logic here
# e.g., @connection.delete(something)
end
def create_phone
# insert your logic here
# e.g., @connection.post(something)
end
end
end
请注意,我们已经换new
了create
; 您不想new
在Ruby中命名方法,在上下文中,我们使用的new
意思是实例化但不保存新对象,而create
意味着实例化并保存新对象。
现在我们已经到了这里,并且现在我们已经通过将它们的逻辑移到其他地方而消除了所有嵌套模块,我们可以看到我们最初设置的父模块是不必要的冗余,并且可以消除它:
class MonthyApiClient
def initialize
# insert your logic here
@client = nil
@connection = nil
end
def create_bike
# insert your logic here
# e.g., @connection.post(something)
end
def delete_bike
# insert your logic here
# e.g., @connection.delete(something)
end
def create_phone
# insert your logic here
# e.g., @connection.post(something)
end
end
然后,您可以实现最初的目标:
client_one = MonthyApiClient.new
client_one.create_bike
client_two = MonthyApiClient.new
client_two.create_phone
经过上述解释,我认为您的原始代码是花费大量时间尝试过早优化的一个示例。最好先计划好您的业务逻辑,并使其尽可能简单。https://softwareengineering.stackexchange.com/a/80094上有一些很好的信息,可能有助于解释这个概念。
我什至没有去尝试优化此处显示的代码,因为我不知道创建和删除自行车和手机之间到底有多少共同点。有了这个功能类,并且对这个应用程序中的其他代码有了更好的了解,我可能会尝试将其DRY(这可能意味着回到具有Client
类的模块以及模块方法或其他类来封装DRY逻辑) ),但尝试还为时过早。
您的最后一个问题是关于如何为模块和类构造文件和目录的,有关更多信息,我将向您介绍Ideal ruby项目结构(包括本网站上的许多其他问题)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句