views:

221

answers:

2

The code bellow is the small starting point for a new way ( for me ) of writing and managing code. Before I loose several weeks and probably state at the end that yes it was stupid idea I thought it would be better to "stress test it" here first.

So here is the idea. Each time there are dependencies of the type when Client ( Envoker) classs uses Server ( class providing some services - called Controller in the example bellow ) the Client would use a static method to a "stub" with name which will be generic enough so that this name would not have to change - for example CreateDynamicTextBox() or RunProcedureGetDataSet() and will pass a configuration object according to which the factory will provide the requested version of the Server class , so each time when there is a stable enough version of Server when new functionalities must be added to it ( or the logic of it should be changed ) and new Server class version will be written. The proposed benefit will be preservation of the flow via the generic method and the passing of the "setting" object.

Is this a bad idea ?! If yes why? Anything positive in this approach ?!

using System;


namespace ControllerFactory
{
  class ClientEnvoker
  {
    static void Main ( string[] args )
    {

      Console.WriteLine ( " START " );
      ClientEnvoker objClientEnvoker = new ClientEnvoker ();

      ControllerFactory objControllerFactory = new ControllerFactory ();

      Console.WriteLine ( " RUN METHOD 1 WITH CONTROLLER 1 WITH CONFIG 1 " );
      objControllerFactory.GenericMethodName ( ControllerFactory.CFSetter.First );

      Console.WriteLine ( " RUN METHOD 2 WITH CONTROLLER 2 WITH CONFIG 2 " );
      objControllerFactory.GenericMethodName ( ControllerFactory.CFSetter.Second );

      Console.WriteLine ( " RUN METHOD 3 WITH CONTROLLER 3 WITH CONFIG 3 " );
      objControllerFactory.GenericMethodName ( ControllerFactory.CFSetter.Second );

      Console.WriteLine ( " END HIT A KEY TO EXIT " );
      Console.ReadLine ();

    } //eof method 

  } //eof class 


  class ControllerFactory
  {
    public enum CFSetter : int
    {
      First = 1,
      Second = 2 , 
      Third = 3
    }

    public void GenericMethodName ( CFSetter objCFSetter )
    {
      Controller c = this.FactoryMethod ( objCFSetter );
      c.ConcreteMethod ();
    } //eof method 

    public Controller FactoryMethod ( CFSetter objCFSetter )
    {
      Controller controllerReturn = null;
      switch (objCFSetter)
      {
        case CFSetter.First:
          controllerReturn = new Controller1 ();
          break;
        case CFSetter.Second:
          controllerReturn = new Controller2 ();
          break;
        case CFSetter.Third:
          controllerReturn = new Controller3 ();
          break;
        default:
          controllerReturn = new Controller1 ();
          break;
      }
      return controllerReturn;
    }

  } //eof class

  #region Controllers
  public abstract class Controller
  {
    public abstract void ConcreteMethod ();
  }


  public class Controller1 : Controller
  {

    public override void ConcreteMethod ()
    {
      Console.WriteLine ( "Controller1 screams according to version 1 logic" );
    }
  } //eof class 

  public class Controller2 : Controller
  {

    public override void ConcreteMethod ()
    {
      Console.WriteLine ( "Controller2 screams according to version 2 logic" );
    }
  } //eof class 


  public class Controller3 : Controller
  {

    public override void ConcreteMethod ()
    {
      Console.WriteLine ( "Controller3 screams according to version 3 logic" );
    }
  } //eof class 

  #endregion Controllers



} //eof namespace
+1  A: 

It's fine to use the factory pattern for something like this. However, FactoryMethod() should be where the logic resides to choose which class to instantiate. Also, if FactoryMethod() is returning type Controller then there is no reason to cast the returned object.

Your RunMethod() would change to something like this...

ControllerFactory cf = new ControllerFactory();
Controller c = cf.FactoryMethod(objCFSetter);
c.Scream();

And your FactoryMethod() would look like this...

Controller controllerReturn = null;
switch (objCFSetter) {
    case CFSetter.First:
      controllerReturn = new Controller1();
      break;
    case CFSetter.Second:  
      controllerReturn = new Controller2();
      break;
    default:
      controllerReturn = new Controller1();
      break;
}
return controllerReturn;
Jon Freeland
Thanks, Jon. I had to paste the code you meant as answer ( There should be syntax highlighting in comments also ; ( and at least some 1000 lines space ; )
YordanGeorgiev
A: 

Thanks , Jon. I think you meant the implementation I am posting bellow ( of course not going to accept it as the answer !). Yes , it seems to be more straightforward than my code above with the strange static method. Still, is this the same "functionality" ? If this type of "hot-swapping" works how often , or in which type of situations it could be used ( I am thinking about dynamic controls generation and dynamic choosing of database providers ).

using System;


namespace ControllerFactory
{
  class ClientEnvoker
  {
    static void Main ( string[] args )
    {

      Console.WriteLine ( " START " );
      ClientEnvoker objClientEnvoker = new ClientEnvoker ();

      ControllerFactory cf = new ControllerFactory ();

      Console.WriteLine ( " RUN METHOD 1 WITH CONTROLLER 1 WITH CONFIG 1 " );
      cf.RunMethod ( ControllerFactory.CFSetter.First );

      Console.WriteLine ( " RUN METHOD 2 WITH CONTROLLER 1 WITH CONFIG 2 " );
      cf.RunMethod ( ControllerFactory.CFSetter.Second );


      Console.WriteLine ( " END HIT A KEY TO EXIT " );
      Console.ReadLine ();

    } //eof method 

  } //eof class 


  class ControllerFactory
  {
    public enum CFSetter : int
    {
      First = 1,
      Second = 2
    }

    public void RunMethod ( CFSetter objCFSetter )
    {
      Controller c = this.FactoryMethod ( objCFSetter );
      c.Scream ();
    } //eof method 

    public Controller FactoryMethod ( CFSetter objCFSetter )
    {
      Controller controllerReturn = null;
      switch (objCFSetter)
      {
        case CFSetter.First:
          controllerReturn = new Controller1 ();
          break;
        case CFSetter.Second:
          controllerReturn = new Controller2 ();
          break;
        default:
          controllerReturn = new Controller1 ();
          break;
      }
      return controllerReturn;
    }

  } //eof class

  #region Controllers
  public abstract class Controller
  {
    public abstract void Scream ();
  }


  public class Controller1 : Controller
  {

    public override void Scream ()
    {
      Console.WriteLine ( "Controller1 screams according to version 1 logic" );
    }
  } //eof class 

  public class Controller2 : Controller
  {

    public override void Scream ()
    {
      Console.WriteLine ( "Controller2 screams according to version 2 logic" );
    }
  } //eof class 

  #endregion Controllers



} //eof namespace
YordanGeorgiev
Well, I did accidentally leave out CFSetter.Third in the switch statement... but yes, this is the same functionality. Basically, Main() doesn't know which type of Controller is going to be instantiated (nor does it care). That is the purpose of the ControllerFactory. You can continue to add different possible classes derived from Controller to modify the Scream() functionality and your code in Main() will never have to change. The situations you listed make perfect sense for using this type of pattern.
Jon Freeland