Command Pattern to the rescue
Recently, I was asked to take an existing library of methods (written in c#) that worked against a particular platform (say Oracle on the backend) and build an equivalent set to work against another platform (say SQLServer). The methods were part of classes that implemented an interface – so for e.g. CheckUserCredentials would be a method inside a SecurityService class which implemented an interface (ISecurityService). I call this problem – the problem of having an existing set of services support multiple platforms (in our case SQL Server and Oracle, but the platforms could easily be ‘Mobile’ and ‘Desktop’).
Approach 1 : Create separate implementations for SqlServer and Oracle
The knee-jerk approach would be to say ‘A-Ha’ – we have an interface – All we need to do is make our SqlServer specific code implement that interface and we are done. So – ‘knee jerk’ approach would be to create a class called SqlSecurityService (which implemented the same ISecurityService) and have a similar OracleSecurityService. While this would have served our purpose, this isn’t our typical interface design problem. You typically use an interface based design to design services that aren’t related to each other. So – if we have a set of security services and a set of Account services, we can use an ISecurityService and an IAccountService interface to expose these separately. There isn’t any common factor between these services. An implementer has the choice of implementing any one or both of the services.
In our current problem though, both the Oracle and the Sql Server platforms share a great deal of commonality. The commonality calls for an inheritance based approach to capture all the common functionality in a base class. However, we still need to leave the interface intact to support existing implementers. This calls for a interface combined with inheritance approach. Just such an approach is described in this related post. However, for the sake of completeness, I wanted to mention a pattern that could be used as an alternative to using the combined inheritance and interface approach. This is the common Command Pattern – described below.
Approach 2 : Leave Current Implementation Intact – use a Command Pattern to handle platform specific code
Leave the current implementation intact – no need for a second implementation. Use a command pattern whenever we encounter a database touch point.
Example SecurityService contains a method CheckUserCredentials. This mostly contains code that is common code to SqlServer and Oracle. When we get to the database specific part, we use a command pattern –
SecurityCommand.Execute(CheckUserCredentials)
public class SecurityCommand : ICommand { public void Execute(string commandName) { if(SQlServer) // SqlServer specific code for CheckUserCredentials else // Oracle specific code for CheckUserCredentials } }
Advantages of Approach 2
- No duplication of code
Disadvantages of Approach 2
- We managed to avoid a separate implementation – but it doesn’t really use our interface based design. The whole purpose of having an interface ISecurityService is wasted.
SUMMARY
Almost every app today follows a service oriented architecture which exposes multiple services. If our app was limited to just that, the above interface based approach coupled with our Service Factory (to return a specific service) would be all that is needed. However, today’s services are not just feature based – but also tend to support multiple platforms. These multiple platforms could be multiple databases (e.g. SQLServer and Oracle on the backend), multiple devices (e.g. Desktop and Mobile), multiple OSes etc. To deal with these multiple platforms, one can take a shortcut approach by using the Command pattern as described in this post. To implement a more complete (not a shortcut) solution, read this related post.
Leave a Reply