在某些情况下,我具有要向其中添加业务逻辑的基本模型。例如,我可能有这样的事情。
class User {
String firstname;
String lastname;
@JsonAdapter(NullAdapter.class)
JsonElement opaqueData;
}
class NullAdapter extends TypeAdapter<JsonElement> {
@Override
public void write(JsonWriter out, JsonElement value) throws IOException {
out.jsonValue(new GsonBuilder().serializeNulls().create().toJson(value));
}
@Override
public JsonElement read(JsonReader in) throws IOException {
// TODO Auto-generated method stub
return null;
}
}
通过常规关联方法,订阅和取消订阅都很容易。
class List < ApplicationRecord
has_many :subscriptions
has_many :subscribers, though: :subscriptions
end
class Subscriber < ApplicationRecord
has_many :subscriptions
has_many :lists, through: :subscriptions
end
class Subscription < ApplicationRecord
belongs_to :list
belongs_to :subscriber
end
但是有日志记录,跟踪,指标,挂钩和其他业务逻辑。我可以通过回调来做到这一点。但是我想保持基本模型的简单和灵活。我的愿望是将核心功能与额外的业务逻辑分开。现在,这是为了简化测试。最终,我需要在同一核心之上添加两组不同业务逻辑。
当前,我正在使用服务对象来包装具有所有当前业务逻辑的常见操作。这是一个简单的例子,还有很多。
# Subscribe
list.subscriptions.create(
subscriber: subscriber
)
# Unsubscribe
list.subscriptions.destroy(subscription)
# Unsub from all lists
subscriber.subscriptions.destroy_all
但是我发现它越来越尴尬。例如,我不能使用自然的class SubscriptionManager
def subscribe(list, subscriber)
list.subscriptions.create( subscriber: subscriber )
log_sub(subscription)
end
def unsubscribe(subscription)
subscription.list.subscriptions.destroy(subscription)
log_unsub_reason(subscription)
end
def unsubscribe_all(subscriber)
subscriber.subscriptions.each do |subscription|
unsubscribe(subscription)
end
subscriber.lists.reset
subscriber.subscriptions.reset
end
end
,但必须小心通过SubscriptionManager方法。 as Pattern,此系统导致难以发现错误。
我正在考虑消除SubscriptionManager,而是编写模型中具有附加逻辑的子类。
subscriber.subscriptions.destroy_all
问题是我发现我必须重复所有关联,以确保托管对象与其他托管对象关联。
有没有更好,更少冗余的方法?
答案 0 :(得分:0)
我不太了解为什么需要在子类中再次定义关联。但是,我有一个提示,您可以直接在您的Subscription
模型中使用。
如果您想保持模型简单,并且不使用回调逻辑重载模型,则可以创建一个callback class来包装该模型将使用的所有逻辑。
为此,您需要创建一个类,例如:
class SubscriptionCallbacks
def self.after_create(subscription)
log_sub(subscription)
end
def self.after_destroy(subscription)
log_unsub_reason(subscription)
end
end
然后在Subscription
模型中:
class Subscription < ApplicationRecord
belongs_to :list
belongs_to :subscriber
after_destroy SubscriptionCallbacks
after_create SubscriptionCallbacks
end
这样,您的模型就可以保持整洁,您可以destroy
进行订阅并应用所有自定义逻辑,而无需使用服务。
更新
具体来说,我不明白的是,为什么要在三个模型上进行Single Table Inheritance只是为了向其中之一添加回调。您编写问题的方式,对于三个子类,您将覆盖关联以使用所创建的子类。那真的有必要吗?我认为没有,因为您想要实现的只是将服务重构为回调,以便直接在destroy
模型中使用destroy_all
和Subscription
,因此我从这里开始:< / p>
但是我发现它越来越尴尬。例如,我不能使用自然的subscriber.subscriptions.destroy_all,但必须小心使用SubscriptionManager方法。
使用conditional callbacks也许就足够了,或者甚至可以使用Subscription
模型上的普通回调。
我不知道实际的代码是如何编写的,但是我发现使用“单表继承”来添加回调很棘手。那不会使您的模型“简单而灵活”。
更新2
在回调类中,使用要实现的回调的名称定义方法,并将subscription
作为参数传递。在这些方法内部,您可以创建所需的所有逻辑。例如(假设给定type
属性,您将使用不同的逻辑):
class SubscriptionCallbacks
def after_create(subscription)
if subscription.type == 'foo'
log_foo_sub(subscription)
elsif subscription.type == 'bar'
log_bar_sub(subscription)
end
end
private
def log_foo_sub(subscription)
# Here will live all the logic of the callback for subscription of foo type
end
def log_bar_sub(subscription)
# Here will live all the logic of the callback for subscription of bar type
end
end
这可能是很多逻辑,不会在Subscription
模型中编写。您可以照常使用destroy
和destroy_all
,如果if else
中未定义订阅类型,则不会发生任何事情。
所有回调逻辑都将包含在callback class
中,并且您将添加到subscription
模型中的唯一代码是:
class Subscription < ApplicationRecord
belongs_to :list
belongs_to :subscriber
after_create SubscriptionCallbacks.new
end