I’ve been working with a programmer recently who is new to both design patterns and object oriented programming. He’s been maintaining some old code I wrote a while back and trying to change how it behaves. Obviously, this could be challenging for someone who’s new to OO.
So, the other day he asked me to explain what Service Objects are. I tried to explain the nature of the Faade design pattern and how a service is simply a faade for more complex operations in your system. I tried to explain that it’s a good practice to wrap all of your model objects to make it easier to expose this functionality to various systems.
Honestly I wasn’t terribly successful with this explanation. In his particular case his service was going to use a gateway object (yet another design pattern) to get a query and return it. But, if the service is returning a query, how does the service differ from the gateway?
I had to think about how to explain this, and what I came up with was this analogy:
Let’s say I ask you to get me a nice frosty mug of beer. If you agree to get me this cool, refreshing, beer, you’ll be performing the service of getting a beer. You, you’re a service object. You perform a service.
Now, personally, and I’m not trying to be rude here, I honestly don’t care how you get the beer. You could run to the store and buy a mug, some dry ice, and a six pack. You could go to the neighborhood pub and run off with a fresh drawn beer. More likely, you’ll just walk (heck, you could run or skip, for all I care) to the fridge, grab a beer and poor it into a mug, and bring it back to me. And, just to illustrate my point again, you could use a bottle opener, your teeth or any other mechanism to open the beer. To me, those are just (implementation) details that don’t matter, so long as I get my frosty mug of beer back.
Now, let’s think about what you care about as the service. Do you care how the fridge stays cold? Do you care how it was manufactured? Do you care how the beer was brewed? You might care what brand of beer (microbrews only, please), but chances are that’s already a constraint of the system you’re running in. You don’t care how long the beer was fermented. You don’t care how long the mugs are kept cold to make them frosty. All these details are the responsibility of other systems that, though essential ultimately, to you, my BeerService, being able to successfully get me my beer.
So, lets break the analogy down a bit. Who are the players and what do they represent?
Me/I. I represent any system which uses your service. I could be a remote faade used by flex. I could be a controller in your MVC framework. I could be another service that just really needs a beer.
You. You’re a BeerService component (or maybe a BarTenderService). You have a set of methods related to beer (or bartending, I guess, as the case may be). For example, getBeer(), restockBeer(), cleanMugs(), wipeUpSpills(), cutOffUser(), etc. As the user of the service, I don’t care how you get these things done, you just do them, far as I’m concerned.
The Fridge, The Beer, The Mug, etc. These are components within your application’s model. In real computer systems these are objects that have specific responsibilities. For instance, the mug in our system is responsible for being frosty and holding beer. In a real system you might have a BeerGateway that is responsible for listing beers in your database.
I hope that helps clarify things!