在 Ruby 中惯用地创建外观
Creating facade idiomatically in Ruby
我来自 Java,正在尝试用惯用的 Ruby 实现 Facade。我可以看到 Rails' ActiveRecord
喜欢使用 class 方法来处理 find_by(criteria)
之类的事情,并且不为该任务使用存储库模式。
我的 Facade 使用多种方法包装特定的 Web 服务。我最初的想法是API类似于ActiveRecord
(模仿学习):
class MyEntity
# ....
def get_name
@loaded_name + @loaded_surname
end
def delete
@entity_access_service.delete(@id)
end
def save
@entity_access_service.save(@id, @loaded_name , @loaded_surname)
end
def self.find(id)
data = @entity_access_service.get_data_for(id)
MyEntity.new(data) #Or whatever way to populate my entity
end
end
从理论上讲,这会很有效:
e = MyEntity.find(10)
p e.get_name
e.delete
或者:
e = MyEntity.new(some stuff)
e.save
问题:
为了使 save
和 delete
实例方法起作用,我需要以某种方式获取 EntityAccessService
的实例。该实例应该是可模拟的,以便在隔离环境中对其进行测试。正确的做法是什么?
我希望我的测试看起来尽可能简单并且没有一些奇怪的技巧,因为我试图实现的东西看起来相当微不足道。
我想到了几种选择:
有一个 class 级变量保存 entity_access_service
由应用程序中创建的所有实体使用。这样的话,应该在哪里初始化这个字段呢?例如:
class MyEntity
@@entity_access_service = nil
end
# Somewhere else (where?):
MyEntity.entity_access_service = MyEntityService.new(some_params_from_env)
这样,在我的测试中,我必须在开始时 initialize/mock 它。
与1类似,但在class中初始化。这看起来很奇怪,特别是如果我知道我的测试根本没有填充必需的 ENV 参数。
多了一个constructor/attribute来设置entity_service
。这不会起作用,因为 save
不会初始化此字段。
创建一个Repository
class。这会工作得很好,但似乎不是 Ruby 人们所做的。
按照 ActiveRecord 的示例,您可以在 class 本身或派生其他 class 的基础 class 上创建一个方法。
ActiveRecord 提供了一个方法ActiveRecord::Base.connection
,其中returns 连接对象,所有模型都使用它来访问数据库。你可以做类似的事情:
class MyEntity
....
def self.entity_access_service
# return your service object
end
def self.find(id)
MyEntity.entity_access_service.get_data_for(id)
MyEntity.new(data) # Or whatever way to populate my entity
end
def save()
MyEntity.entity_access_service.save(@id, @loadedName, @loadedSurname)
end
end
就初始化而言,您要么必须在您的应用程序(和测试套件)中有一个初始化步骤,其中服务凭证从配置文件中读取并传递到您的 MyEntity
对象中, 或 您的 entity_access_service
方法可以在第一次访问时使用非常常见的 Ruby 惯用语懒惰地创建对象 returns:
def self.entity_access_service
@entity_access_service || = # build entity_access_service object
end
请注意,通过将 class 级实例变量包装在 class 级访问器方法中,您可以避免使用 @@
这是一个 recommended best practice .
我来自 Java,正在尝试用惯用的 Ruby 实现 Facade。我可以看到 Rails' ActiveRecord
喜欢使用 class 方法来处理 find_by(criteria)
之类的事情,并且不为该任务使用存储库模式。
我的 Facade 使用多种方法包装特定的 Web 服务。我最初的想法是API类似于ActiveRecord
(模仿学习):
class MyEntity
# ....
def get_name
@loaded_name + @loaded_surname
end
def delete
@entity_access_service.delete(@id)
end
def save
@entity_access_service.save(@id, @loaded_name , @loaded_surname)
end
def self.find(id)
data = @entity_access_service.get_data_for(id)
MyEntity.new(data) #Or whatever way to populate my entity
end
end
从理论上讲,这会很有效:
e = MyEntity.find(10)
p e.get_name
e.delete
或者:
e = MyEntity.new(some stuff)
e.save
问题:
为了使 save
和 delete
实例方法起作用,我需要以某种方式获取 EntityAccessService
的实例。该实例应该是可模拟的,以便在隔离环境中对其进行测试。正确的做法是什么?
我希望我的测试看起来尽可能简单并且没有一些奇怪的技巧,因为我试图实现的东西看起来相当微不足道。
我想到了几种选择:
有一个 class 级变量保存
entity_access_service
由应用程序中创建的所有实体使用。这样的话,应该在哪里初始化这个字段呢?例如:class MyEntity @@entity_access_service = nil end # Somewhere else (where?): MyEntity.entity_access_service = MyEntityService.new(some_params_from_env)
这样,在我的测试中,我必须在开始时 initialize/mock 它。
与1类似,但在class中初始化。这看起来很奇怪,特别是如果我知道我的测试根本没有填充必需的 ENV 参数。
多了一个constructor/attribute来设置
entity_service
。这不会起作用,因为save
不会初始化此字段。创建一个
Repository
class。这会工作得很好,但似乎不是 Ruby 人们所做的。
按照 ActiveRecord 的示例,您可以在 class 本身或派生其他 class 的基础 class 上创建一个方法。
ActiveRecord 提供了一个方法ActiveRecord::Base.connection
,其中returns 连接对象,所有模型都使用它来访问数据库。你可以做类似的事情:
class MyEntity
....
def self.entity_access_service
# return your service object
end
def self.find(id)
MyEntity.entity_access_service.get_data_for(id)
MyEntity.new(data) # Or whatever way to populate my entity
end
def save()
MyEntity.entity_access_service.save(@id, @loadedName, @loadedSurname)
end
end
就初始化而言,您要么必须在您的应用程序(和测试套件)中有一个初始化步骤,其中服务凭证从配置文件中读取并传递到您的 MyEntity
对象中, 或 您的 entity_access_service
方法可以在第一次访问时使用非常常见的 Ruby 惯用语懒惰地创建对象 returns:
def self.entity_access_service
@entity_access_service || = # build entity_access_service object
end
请注意,通过将 class 级实例变量包装在 class 级访问器方法中,您可以避免使用 @@
这是一个 recommended best practice .