class TaxRemoteFacadeI've only shown two, but we actually needed the
def state_tax
...
@remote.close
end
def federal_tax
...
@remote.close
end
end
@remote.close
code at the end of several methods.Solution: To reduce the duplication you could introduce a mixin with a method to remove the duplication.
module RemoteFacadeThe TaxRemoteFacade can now be defined as the code below.
def remote_call(method_name, &block)
class_eval do
define_method name do
instance_eval &block
@remote.close
end
end
end
end
class TaxRemoteFacade
extend RemoteFacade
remote_call do :state_tax do
...
end
remote_call do :federal_tax do
...
end
end
Neat trick - is there any reason why you'd choose a superclass over a mixin?
ReplyDeleteIn my particular instance we already had the superclass so it seemed like it made sense. However, I do prefer mixins. Good catch.
ReplyDeleteOooh, a little slick ad hoc AOP, eh?
ReplyDeleteVerra nice.
I'd like to suggest an alternative
ReplyDeletemodule Remote
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def remote_methods(*names)
names.each do |name|
define_method("#{name}_with_remote") do |*args|
begin
send("#{name}_without_remote", *args)
ensure
@remote.close
end
end
alias_method_chain(name, :remote)
end
end
end
end
class TaxFacade
def state_tax
...
end
def federal_tax
...
end
end
# Somewhere else...
class TaxFacade
include Remote
remote_methods :state_tax, :federal_tax
end
Contrary to what Dan writes, the original approach is not AOP at all as it intermingles concerns. That's what I've tried to avoid with my alternative.
Good OOP solution! It's nice to see someone applying OOP patterns instead of "how Ruby crazy can I get"? For the record, you've just implemented the Template Pattern. It's one of my favorites.
ReplyDelete@Seth: I'm not convinced my suggestion really is an instance of the Template Method pattern. There's a similarity, of course, but compared to Template Method, mixing in + aliasing put things upside down.
ReplyDeleteWith Template Method, you have a base class that defines an algorithmic skeleton, and subclasses that fill in the concrete steps. The base class comes before its subclasses.
In my suggestion, the TaxFacade comes first. Then another (singleton) class containing templates is snug in as its superclass and TaxFacades methods are redefined to fit in the templates.
Let's call it Inverse Template Mixin pattern. In AOP terms, it is after advice applied to an execution pointcut.
the day comes and you realize that one or more of those methods needs to return some other value. then all your fancy metacode is for shit. unless you have a real Aspect don't bother.
ReplyDeletebtw check out:
http://groups.google.com/group/ruby-talk-google/browse_thread/thread/a42156ab1c955941/5d908fb73dd885dc?lnk=gst&q=trans+aop+bending&rnum=1&hl=en#5d908fb73dd885dc
The idea on this post wasn't meant to address Aspects in Ruby. In fact the only responsibility of the class is to call the tax remote facade. And, the idea of the post was how to remove some duplication.
ReplyDeleteI was hesitant to bring this up since I do want to encourage other implementations and fresh ideas, but I think the comments have gotten a bit off topic.