& # 8220; Conjunto de definiciones de intermediario & # 8221; patrón de diseño & # 8212; ¿Conocido bajo otro nombre?

StackOverflow https://stackoverflow.com/questions/401720

Pregunta

En un proyecto en el que he estado involucrado durante muchos años, gradualmente he desarrollado un patrón de diseño que ha demostrado ser extremadamente útil para mí. A veces siento que debería ser un poco evangélico con eso, pero me avergonzaría si lo intentara y descubriera que era solo mi versión del viejo sombrero de alguien. He buscado en Patrones de diseño en vano, y no he encontrado a nadie más hablando de ello, pero mi búsqueda no ha sido exhaustiva.

La idea central es tener un objeto de intermediario que gestione un conjunto de objetos de definición, y cada objeto de definición constituye un posible valor de alguna propiedad compleja. Como ejemplo, es posible que tenga clases de Car, Plane y Generator que tengan un EngineType. El automóvil no almacena su propio objeto EngineType, almacena una clave de referencia de algún tipo que indica el tipo de motor que tiene (como un número entero o ID de cadena). Cuando queremos ver las propiedades o el comportamiento de un EngineType, digamos WankelEngine, le pedimos al objeto Singleton EngineTypeBroker para el objeto de definición de WankelEngine, pasándole la clave de referencia. Este objeto encapsula todo lo que es interesante saber acerca de los tipos de motor, posiblemente simplemente como una lista de propiedades pero también puede tener un comportamiento cargado en él.

Entonces, lo que está facilitando es un tipo de agregación compartida y poco acoplada, en la que muchos Cars pueden tener un WankelEngine pero solo hay un objeto de definición de WankelEngine (y EngineTypeBroker puede reemplazar ese objeto, aprovechando el acoplamiento suelto en el morfismo mejorado en tiempo de ejecución ).

Algunos elementos de este patrón como lo uso (continúo usando EngineType como ejemplo):

  1. Siempre hay funciones IsEngineType (x) y EngineType (x), para determinar si un valor dado es una clave de referencia válida para un EngineType y para recuperar el objeto de definición EngineType correspondiente a una clave de referencia, respectivamente.
  2. Siempre permito múltiples formas de clave de referencia para un EngineType determinado, siempre al menos un nombre de cadena y el objeto de definición en sí mismo, más a menudo que no un ID entero, y algunas veces los tipos de objetos que agregan un EngineType. Esto ayuda con la depuración, hace que el código sea más flexible y, en mi situación particular, facilita muchos problemas de compatibilidad con versiones anteriores en relación con las prácticas anteriores. (La forma habitual en que la gente solía hacer todo esto, en el contexto de este proyecto, era definir los hashes para cada propiedad que pudiera tener un EngineType y buscar las propiedades por clave de referencia).
  3. Generalmente, cada instancia de definición es una subclase de una clase general para ese tipo de definición (es decir, WankelEngine hereda EngineType). Los archivos de clase para los objetos de definición se guardan en un directorio como / Def / EngineType (es decir, la clase de WankelEngine sería / Def / EngineType / WankelEngine). Por lo tanto, las definiciones relacionadas se agrupan y los archivos de clase se asemejan a los archivos de configuración para EngineType, pero con la capacidad de definir el código (que normalmente no se encuentra en los archivos de configuración).

Algunos pseudocódigos de ejemplo trivialmente ilustrativos:

class Car {

    attribute Name;
    attribute EngineTypeCode;

    object GetEngineTypeDef() {
        return EngineTypeBroker->EngineType(this->GetEngineTypeCode());
    }

    string GetDescription() {
        object def = this->GetEngineTypeDef();
        return "I am a car called " . this->GetName() . ", whose " .
            def->GetEngineTypeName() . " engine can run at " .
            def->GetEngineTypeMaxRPM() . " RPM!";
    }

}

Entonces, ¿hay un nombre por ahí para esto?

¿Fue útil?

Solución

SingletonRegistry

Créeme o no. Estaba pensando lo mismo esta mañana.

He usado este patrón anteriormente, pero nunca he encontrado una referencia para él ni sé cómo nombrarlo.

Creo que es una especie de " Clave " Singleton, donde las instancias se almacenan en algún lugar y se obtienen mediante una clave.

La última vez que lo usé fue para recuperar datos de diferentes fuentes.

Tenía alrededor de 50 tablas de base de datos (hazlo con 10) Y tengo una parte delantera de " tabla " donde se mostrarían los datos, pero los datos podrían provenir de cualquiera de esas fuentes y cada una requiere una lógica diferente (consultas, combinaciones, claves, etc.)

Este extremo frontal era " configurable " así que no podía saber qué valores se mostrarían y cuáles otros no.

La solución fue tomar la columna Nombre (en el extremo frontal) como la clave y obtener la instancia correcta para crear la consulta correcta.

Esto se instaló en un mapa hash al principio y luego se recuperó de una tabla de base de datos.

El código era así:

class DataFetcher {
    abstract Object getData( Object id );
}

class CustomerNameDataFetcher extends DataFetcher {
    Object getData( Object customerId ) { 
        // select name from customer where id = ? 
     }
}

class CompanyAdressDataFetcher extends DataFetcher { 
     Object getData( Object customerId ) { // don't ask why.
          // select name from company , customer where customer.co = company.co and cu = ?  etc.
     }
} 

class ProductColor extends DataFetcher { 
     Object getData( Object x ) { 
     // join from customer to color, to company to season to a bunch of table where id = ? 
}

// And the list goes on.

Cada subclase utiliza una lógica diferente.

En el tiempo de ejecución, el usuario configuró su vista y seleccionó lo que desea ver.

Cuando el usuario seleccionó las columnas para ver, usé el nombre de la columna y una identificación para recuperar los datos.

Todos los DataFetchers se instalaron en la clase principal (no quería tener una clase separada para esto) en un método de clase.

class DataFetcher {
    abstract Object getData( Object id );

    private static final Map fetchers = new HashMap();static { 
        fetchers.put("customer.name", new CustomerNameDataFetcher() );
        fetchers.put("company.address", new CompanyAdressDataFetcher () );
        fetchers.put("product.color", new ProductColor () );
        ...
    }
    public static DataFetcher getFetcher( String id ) { 
        return fetchers.get( id );
    }      

}

Al final para completar la tabla frontal, solo lo llamo así:

pseudocode

 for each row in table 
      for each column in row
          column.text = DataFetcher.getFetcher( column.id ).getData( row.id )
       end
 end

¿Es así? ¿O no leo su descripción y la mía es bastante diferente?

Finalmente, creo que esto se llama SingletonRegistry o algo así. Yo (probablemente) como tú, creé esto por necesidad. Lo más probable es que este es un patrón común.

Otros consejos

He usado un patrón similar a este antes, la mayoría de las veces en juegos. Tendría clases de WeaponDefinition y WeaponInstance (no con esos nombres). La clase WeaponDefinition (y varias subclases, si tengo diferentes tipos de armas, p. Ej. Cuerpo a cuerpo vs proyectil) sería responsable de mantener un registro de los datos globales para ese tipo de arma (tasa de fuego, munición máxima, nombre, etc.) y tiene Toda la lógica. La clase WeaponInstance (y las subclases) contiene el estado actual en la secuencia de disparo (para usar con la comparación de la velocidad de disparo), el recuento de munición actual y un puntero (podría ser alguna clave en una clase de administrador como en su ejemplo, pero eso no parece ser un requisito del patrón) para la Definición de Armas. WeaponInstance tiene un montón de funciones para disparar, recargar, etc., que solo llaman al método apropiado en la instancia de WeaponDefinition, pasándose a sí mismo como un argumento. Esto significa que las cosas de WeaponDefinition no se han duplicado para cada tanque / soldado / avión en el mundo del juego, pero todos tienen sus propios conteos de municiones, etc.

No tengo idea de cómo se llama, y ??no estoy seguro de que sea lo mismo de lo que estás hablando, pero creo que está cerca. Es definitivamente útil.

Suena como una combinación de GoF Builder, Prototype y quizás Featherweight para mí.

Parece una variedad de peso mosca (muchos autos comparten un motor Wankel). Pero, ¿cómo tiene eso sentido? La mayoría de los automóviles tienen un motor, pero ¿cómo pueden muchos de ellos tener la misma instancia de un motor? No llegarían lejos de esa manera. ¿O quiere decir que muchos coches tienen un motor de tipo WankelEngine? Spose que tiene más sentido. Entonces, ¿cuál es el uso del " Objeto de definición de WankelEngine " ;? ¿Es una Fábrica que está creando sabores de ese objeto y devolviéndolos al solicitante? Si es así, no suena como un objeto de definición, suena más como una Fábrica que está tomando los parámetros del objeto para construir y devolver ese objeto.

Veo algunas buenas prácticas de GoF aquí, específicamente que estás componiendo en lugar de heredar (mi Coche tiene un Motor y el Motor de mi Coche es un Motor de Wankel). Me gustaría poder recordar la cita exactamente, pero es algo así como "la herencia rompe la encapsulación" y "favorecer la composición sobre la herencia".

Tengo curiosidad por saber qué problema se resuelve con esto. Creo que ha agregado mucha complejidad y no veo la necesidad de tal complejidad. Tal vez sea algo específico de tu idioma que no entiendo.

Los chicos de GoF sí discuten la composición de patrones en patrones más grandes, MVC en particular es un conjunto de otros tres patrones. Parece que has hecho algo así.

Suena un poco como el Localizador de servicios, en el que sus pesos pluma se registran como singletons.

Lo que tienes es un mapa, también conocido como Diccionario. Solo tiene un giro único al tener varias claves asignadas a un objeto.

Por qué es un mapa:

  • mantener una clave
  • Use la tecla para consultar un valor de alguna estructura de datos.

Puedes encontrar implementaciones en:

  • STL (incluye: mapa)
  • Java (import: java.util.Dictionary)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top