我正在尝试用来自Java的惯用Ruby实现Facade。我可以看到Rails'ActiveRecord
喜欢在find_by(criteria)
之类的东西上使用类方法,并且不使用Repository模式来完成该任务。
My 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
的实例。此实例应该是可模拟的,以便在隔离环境中对其进行测试。这样做的正确方法是什么?
我希望我的测试看起来尽可能简单,没有一些奇怪的黑客,因为我正在尝试实现它似乎相当微不足道。
我想到了几个选项:
拥有在应用程序中创建的所有实体使用的entity_access_service
的类级变量。在这种情况下,我应该在哪里初始化此字段?例如:
class MyEntity
@@entity_access_service = nil
end
# Somewhere else (where?):
MyEntity.entity_access_service = MyEntityService.new(some_params_from_env)
这样,在我的测试中,我必须在开始时初始化/模拟它。
与1类似,但在课堂上初始化它。这看起来很奇怪,特别是如果我知道我的测试根本没有填充所需的ENV参数。
有一个额外的构造函数/属性来设置entity_service
。这不起作用,因为save
不会初始化此字段。
创建Repository
课程。这样做会很好,但似乎不是Ruby人所做的。
答案 0 :(得分:1)
在ActiveRecord的示例之后,您可以在类本身或者从其他类派生的基类上创建方法。
ActiveRecord提供了一个方法ActiveRecord::Base.connection
,它返回所有模型用来访问数据库的连接对象。你可以做类似的事情:
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习语:
def self.entity_access_service
@entity_access_service || = # build entity_access_service object
end
请注意,通过将类级实例变量包装在类级访问器方法中,可以避免使用@@
recommended best practice。