We have an application that contacts several diffrent remote services(SOAP, HTTPREQUEST). We then do different actions(import, export, update, delete).
Today we have two client classes and four action classes.
QUESTION!
How can I decouple these two modules so that I have to do the least changes. IE only add a new action/new client. Nothing more.
Client class
Authorizes our client against the remote service, it handles logging in and out.
Action class
Holds the url, method to invoke against the client. Aswell as the ExecuteActionMethod
Usage
Client class get's decorated with an action and then performs the action with the client.
Fears
I dont want to:
- create a new action class everytime I add a new client class
- create a new client class everytime I add a new action class
- No god object factory that needs to know everything
Problem
The problem with this approach is that when talking to different clients, I need diffrent information in this case different URLS, talking to the Soap service needs invoking of the correct method. The action itself is the keeper of this information. But as I dig deeper this certainly is something that will change.
Scenario 1#
I end up creating classes that combine both action and result. So I have classes like "HttpImport"(based on HttpClient and ImportAction). Which results in X(Clients) * Y(Actions) which now would total at 8 classes, which is really bad.
Scenario 2#
Time for some code! In this scenario the implementation binds my classes together even though I use abstractions.
Problem here is that every action need to have a property for each of the clients(remember they visit different endpoints). So if i were to add one more client I would have to go through all the actions and add another property for that clients endpoint, aswell as add another deocrator to delegete all calls to the correct endpoint(remember i have three properties now in every action). If I were to create another action, it would just be that action. So N*times actions + 1(the action), in this case 5 changes. A little bit better but still not there.
Scenario 3#
This is the God object factory. Here we get rid of the properties holding the endpoints, and we supply the enpoint via the constructor. This will result in methods for creating all sorts of clients and actions. Same as above X(Clients) * Y(Actions) if something were to be added, these accumulate into 8 new methods inside the factory. The factory must also hold endpoint information.
Code
My code has evolved to the 2:nd scenario. I dont want to build the factory, and I'm looking to you guys.
Something tells me that the client classes does to much and should somehow be decoupled, from the classes they instansiate inside.
Main
static void Main(string[] args)
{
IAction iact = new ImportAction();
IDecorator idec = new HttpDecorator(iact);
IClient icli = new HttpClient(idec);
Console.Write(icli.connect().ToString());
Console.ReadKey();
}
IAction
public interface IAction
{
string[] Execute();
string HttpString { get; }
string SoapMethod { get; }
}
ImportAction
class ImportAction : IAction
{
private string soapmethod;
private string httpUrl;
public ImportAction()
{
this.HttpString = @"http://ift.tt/1FNt15j";
}
public string[] Execute()
{ //Execute the action!
return null;
}
public string HttpString { get; set; }
public string SoapMethod { get; set; }
}
IDecorator
public interface IDecorator
{
string GetActionString();
}
HttpDecorator
class HttpDecorator : IDecorator
{
private IAction _action;
public HttpDecorator(IAction action)
{
this._action = action;
}
public string GetActionString()
{
return _action.HttpString;
}
public string[] Execute()
{
throw new NotImplementedException();
}
}
IClient
public interface IClient
{
bool connect();
}
HttpClient
class HttpClient : IClient
{
private string _username;
private string _password;
private IDecorator _myaction;
private HttpWebRequest webReq;
public HttpClient(IDecorator action)
{
this._username = "myusername";
this._password = "mypassword";
this._myaction = action;
}
public bool connect()
{
bool result = false;
webReq = (HttpWebRequest)WebRequest.Create(_myaction.GetActionString());
webReq.Credentials = new NetworkCredential(_username, _password);
HttpWebResponse myHttpWebResponse = (HttpWebResponse)webReq.GetResponse();
if (myHttpWebResponse.StatusCode == HttpStatusCode.OK)
{
result = true;
}
return result;
}
}
Aucun commentaire:
Enregistrer un commentaire