Loosley defer a method/interface?
I have been working on a sub-system that is a bit of a service gateway, and ran into an instance where I wish I could have loosely defined an interface. After going through the design, and review, I had such a pretty picture of how the whole api would work. As expected, come implementation time, a couple things changed, and a line that I had thought would be abstracted ended up being typed. No problem.... until I wanted to force consistency in concrete implementations.
After looking at the design again (read trying to justify the abstraction), I was left with this empty feeling about the api. The meat of the implementations would be in the concrete classes, but I had no way to control them anymore. Now you might think that’s not my responsibility, I'm way down here, and up there, well they can do what they want. Besides my professional responsibility for the whole api, I also felt as if there is justification for loosely defining an interface at this level, and that it could possibly add value.
So, what do I mean? Consider a big buffet restaurant, with lots of different types of foods. To cook all of this, there would be a number of cooks, each with skills in the area they are working. Now, as the manager, I want to tell all of them to cook, but I want different results out of each. I do have to deal with each one individually, but I want to deal with them all in the same manner. I may even have to provide each of them different things, but in the end I still communicate with them the same.
Back to my thought. As an API designer, I think there is value in being able to define the fact that a child must implement something, but how you implement it is totally up to you, including the complete signature. Anyone using this concrete class would need to be typed and couldn't generalize any others like me.
abstract chefBase
{defer Cook()}
public ChineseChef : chefBase
{public Cook : FriedRice}
public ItalianChef : chefBase
{public Cook(sauce) : BakedZiti}
So as a manager, I can tell all of my chefs to cook, no matter which it is. This allows for consistent communication across my entire framewo… kitchen.
So I started to think about it a little more, and there might just be an abstraction point here. As an owner of a number of restaurants, I could now have a managerBase. Could the managerBase call chef.Cook?
My purist mind says no, a managerBase knows way too little about the chef to call an undefined cook. Then I started to think about the essance of the “defer”ing done above, and thought maybe it could. A loose contract must be fulfilled by a concrete instance, so a loose requirement for it could be fulfilled by concrete implementation on the other end.
abstract managerBase
{protected chef;
defer MakeCook(chef.Cook());}
This could allow the two api designers to gaurentee a typed contract with each other, long before having a typed interface. Some would argue that even though the behaviors are loosely coupled, the api's are now tightly coupled, which might negate some value. Agreed, but in some instances there could be value in having that low level coupling.
Anyway, this ends my rant. It's probably crazy, but at least I can stop thinking about it now.