2011-04-25 14 views
7

Conozco un poco acerca de Object Oriented design, pero no estoy seguro de cómo utilizar estos principios en mi código. Esto es lo que estoy trabajando en:¿Cómo puedo diseñar esto mejor? (Evitar una instrucción de conmutación con diseño orientado a objetos)

public void Query(Agency agency, Citation queryCitation) { 
     queryCitation.AgencyCode = agency.AgencyCode; 

     switch (agency.ClientDb.Type) { 
      case "SQL": 
       QueryOracle(agency, queryCitation); 
       break; 
      case "PIC": 
       QueryPick(agency, queryCitation); 
       break; 
     } 
    } 

(.. La mayoría de estos son objetos de NHibernate que estoy trabajando con un sistema de bases de datos existentes y estoy refactorización partes de ella en una biblioteca de código) Claramente, lo que podía hacer algo diferente aquí para que no necesite funciones duplicadas para diferentes consultas de bases de datos que tienen la misma entrada. Solo debe saber, basado en el objeto de la agencia, si usar una base de datos Oracle o una conexión de base de datos Pick. (Si nunca escuchó de una base de datos de Pick, tampoco la tuve hasta que comencé a trabajar aquí. Hacemos consultas a través de solicitudes HTTP, por lo que no es SQL.)

¿Debo hacer una interfaz, para ejemplo llamado "ClientDbConnection" y luego crear dos clases que implementan esa interfaz, mover el código para consultar la base de datos a aquellos y luego tener algo como "agency.clientDb.Query (queryCitation)" reemplazar esta función completa? Creo que estoy pensando en voz alta aquí, pero cualquier comentario sobre esto sería apreciado.

Respuesta

11

¿Es la agencia una clase que usted controla?Si es así hacer algo como esto:

public abstract class GenericDb 
{ 
    public abstract void Query(parms); 
} 

en su clase de la Agencia, que podría tener

public GenericDb ClientDb {get; set;} 

Entonces tienen una clase SQLdb como:

public class SqlDb : GenericDb 
{ 
    public void Query(parms); 
} 

public class PicDb : GenericDb 
{ 
    public void Query(parms); 
} 

Entonces este código:

public void Query(Agency agency, Citation queryCitation) { 
     queryCitation.AgencyCode = agency.AgencyCode; 

     switch (agency.ClientDb.Type) { 
      case "SQL": 
       QueryOracle(agency, queryCitation); 
       break; 
      case "PIC": 
       QueryPick(agency, queryCitation); 
       break; 
     } 
    } 

se convierte en

public void Query(Agency agency, Citation queryCitation) { 
     queryCitation.AgencyCode = agency.AgencyCode; 
     agency.ClientDb.Query(queryCitation); 
    } 

Debido a la herencia, se sabrá que Clientdb tiene una clase base de GenericDb. Se sabrá por el tipo del parámetro Clientdb si debe ejecutar el SQLdb o la PicDb u Oracle, etc.

3

Me refactorizaría para aprovechar una interfaz. Yo probablemente que sea algo como:

public interface IQuery 
{ 
    void Execute(Agency agency, Citation query); 
} 

public class OracleQuery : IQuery 
{ 
    // Implementation 
} 

public class PickQuery : IQuery 
{ 
    // Implementation 
} 

A continuación, podría cambiar la clase Agencia para almacenar una instancia de un objeto IQuery en lugar de (o además de) el objeto ClientDb:

public class Agency 
{ 
    public IQuery Query { get; set; } 
} 

Y a continuación, en el código de inicialización (donde normalmente establecer la propiedad ClientDb), podría configurar la instancia de la aplicación apropiada IQuery:

agency.Query = new PickQuery(); 
2

ADO.NET tiene un conjunto de clases genéricas: DbCommand, DbConnection, etc ... que también implementar otra serie de interfaces genéricas: IDbCommand, IDbConnection, etc ...

por lo que podría usarlas, pero puede llegar a ser bastante complicado al final. La ventaja de su solución es que es muy legible. Además, tal vez la base de datos de selección no tiene ningún proveedor de ADO.NET ...

PD: Sin embargo, reemplazaría el tipo de propiedad Tipo y usaría una enumeración.

5

Es probable que desee implementar el patrón de estrategia aquí. Básicamente, cada uno de sus posibles "tipos" en su declaración de cambio se convertiría en una clase propia que implementa la misma interfaz.

Applying the Strategy Pattern

continuación, puede utilizar un método de fábrica que toma un valor "tipo" como parámetro. Ese método devolvería la clase correcta (su tipo de devolución es la interfaz mencionada anteriormente).

0

Hay dos soluciones de programación orientada a objetos y polymorphismVisitor pattern.

+0

¿Puedes explicarlo? Las respuestas de solo enlace no son bienvenidas en Stackoverflow. –

2

Para escribir menos código pero mejorar la legibilidad, el nivel de código declarativo puede pasar al diccionario con delegados para cada base de datos. Eso se puede extender fácilmente y es muy legible. Con ese enfoque más funcional en mente, obtienes algo como

void Query(Agency agency, Citation queryCitation) 
{ 
    Dictionary<string, Action<Agency, Citation>> QueryMap = new Dictionary<string, Action<Agency, Citation>> 
    { 
     { "SQL", QueryOracle}, 
     { "PIC", QueryPic} 
    }; 


    queryCitation.AgencyCode = agency.AgencyCode; 

    QueryMap[agency.ClientDb.Type](agency, queryCitation); 
} 
Cuestiones relacionadas