Pergunta

Em um projeto que eu estive envolvido com por muitos anos, eu já evoluiu gradualmente um padrão de design que está provado ser extremamente útil para mim. Às vezes eu sinto que eu deveria obter um evangélico pouco com ele, mas eu seria um pouco constrangido se eu tentei e descobri que era apenas minha versão do velho chapéu de alguém. Cavei já através de Design Patterns procurando em vão, e eu não ter executado através de qualquer outra pessoa a falar sobre isso, mas a minha pesquisa não foi exaustiva.

A idéia central é ter um objeto corretor que gerencia um conjunto de objetos de definição, cada objeto definição constituindo um possível valor de alguma propriedade complexa. Como exemplo, você pode ter aulas de carro, avião e gerador que todos têm um EngineType. O carro não armazenar seu próprio objeto EngineType, ele armazena uma chave de referência de algum tipo que declara o tipo de motor que tem (como um inteiro ou string ID). Quando queremos olhar para as propriedades ou comportamento de um EngineType, dizem WankelEngine, pedimos ao EngineTypeBroker singleton objeto para objeto de definição do WankelEngine, passando a chave de referência. Este objeto encapsula tudo o que é interessante para saber sobre EngineTypes, possivelmente simplesmente ser uma lista de propriedades, mas potencialmente ter comportamento carregado para ele também.

Então, o que é facilitador é um tipo de compartilhada, agregação fracamente acoplado, onde muitos carros podem ter um WankelEngine mas há apenas um objeto de definição WankelEngine (eo EngineTypeBroker pode substituir esse objeto, aproveitando o baixo acoplamento em morphism runtime reforçada ).

Alguns elementos deste padrão, como eu usá-lo (continuar a usar EngineType como um exemplo):

  1. Há sempre IsEngineType (x) e EngineType funções (x), para determinar se um dado valor é uma chave de referência válida para um EngineType e para recuperar o objecto definição EngineType correspondente a uma chave de referência, respectivamente.
  2. Eu sempre permitem múltiplas formas de chave de referência para um determinado EngineType, sempre pelo menos um nome de cadeia e do próprio objeto de definição, mais frequentemente do que não um ID inteiro, e às vezes os tipos de objetos que agregam um EngineType. Isto ajuda com a depuração, torna o código mais flexível, e, na minha situação particular, facilita um monte de problemas de compatibilidade em relação a práticas mais velhos. (A forma como as pessoas habituais usados ??para fazer tudo isso, no âmbito deste projecto, foi definir hashes para cada propriedade uma EngineType pode ter e olhar para cima as propriedades de chave de referência.)
  3. Normalmente, cada instância definição é uma subclasse de uma classe geral para esse tipo de definição (ou seja WankelEngine herda EngineType). arquivos de classe para objetos de definição são mantidos em um diretório como / Def / EngineType (ou seja, a classe de WankelEngine seria / Def / EngineType / WankelEngine). definições de modo relacionados são agrupados juntos, e os arquivos de classe se assemelham arquivos de configuração para o EngineType, mas com a capacidade de definir o código (não normalmente encontrados em arquivos de configuração).

Alguns pseudocódigo amostra trivialmente ilustrativo:

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!";
    }

}

Assim, há um nome lá fora para isso?

Foi útil?

Solução

SingletonRegistry

Acredite ou não. Eu estava pensando a mesma coisa esta manhã.

Eu tenho usado este padrão antes, mas eu nunca encontrei uma referência para ele nem sabe como nomeá-lo.

Eu acho que é uma espécie de singleton "com chave", onde os casos são armazenados em algum lugar e eles são obtidos utilizando uma chave.

A última vez que eu usá-lo era para recuperar dados de diferentes fontes.

Eu tinha cerca de 50 mesas de banco de dados (torná-lo 10) E eu tenho uma "mesa" front end onde os dados estavam a ser exibido, mas os dados poderiam vir de qualquer uma dessas fontes e cada um requer diferentes lógicas (consultas, junta-se, chaves, etc.)

Esta extremidade dianteira era "configurável" então eu não podia saber o que os valores eram para ser mostrado e que outro não.

A solução foi levar o columnName (no front-end) como a chave, e obter a instância correta para criar a consulta direita.

Esta foi instalado em um mapa de hash no início e mais tarde recuperado de uma tabela de banco de dados.

O código foi assim:

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 subclasse usada lógica diferente.

Em tempo de execução o usuário configurado de vista, e selecione o que ele quer ver.

Quando o utilizador seleccionado das colunas para ver, utilizei o nome da coluna e um ID para buscar os dados.

Os DataFetchers foram todos instalados na classe pai (eu não quero ter uma classe separeate para isso) em um método de classe.

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 );
    }      

}

No fim de preencher a mesa final frente eu só chamá-lo assim:

pseudocódigo

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

É assim? Ou eu descaracterizou sua descrição eo meu é bem diferente.

Finalmente eu acho que isso é chamado SingletonRegistry ou algo parecido. I (provavelmente) como você, criei este em caso de necessidade. As chances são de que este é um padrão comum.

Outras dicas

Eu usei um padrão semelhante a este antes, na maioria das vezes em jogos. Eu teria um WeaponDefinition e aulas WeaponInstance (não exatamente com esses nomes). A classe WeaponDefinition (e várias subclasses, se eu tiver diferentes tipos de armas, por exemplo, corpo a corpo vs projétil) seria responsável por manter o controle dos dados globais para esse tipo de arma (taxa de fogo, munição max, nome, etc) e tem toda a lógica. A classe WeaponInstance (e subclasses) contêm o estado atual na sequência de disparo (para uso com comparando a taxa de incêndio), a contagem de munição atual, e um ponteiro (que poderia ser alguma chave em uma classe gerente como no seu exemplo, mas que não parece ser uma exigência do padrão) para o WeaponDefinition. O WeaponInstance tem um monte de funções para disparar, recarregando, etc, que é só chamar o método apropriado na instância WeaponDefinition, passando-se como um argumento. Isto significa que o material WeaponDefinition não é dupicated para cada tanque / soldado / avião no mundo do jogo, mas todos eles têm as suas próprias contagens de munição, etc.

Eu não tenho idéia o que é chamado, e eu não tenho certeza que é exatamente o mesmo que o que você está falando, mas eu acho que é perto. É definitivamente útil.

soa como uma combinação de GoF Builder, Prototype, e talvez Pena para mim.

Parece uma variedade de um Flyweight (muitos carros compartilham um WankelEngine). Mas como é que isso faz sentido? A maioria dos carros têm um motor, mas como pode muitos deles têm a mesma instância de um motor? Eles não iria longe assim. Ou você quer dizer que muitos carros têm um motor do tipo WankelEngine? Spose que faz mais sentido. Então qual é o uso do "objeto de definição WankelEngine"? É uma fábrica que está construindo sabores desse objeto e passá-los de volta para o solicitante? Se assim não soa como um objeto de definição, soa mais como uma fábrica que está tomando nos parâmetros do objeto a construção e dando a esse objeto de volta.

Eu vejo algumas práticas boa GoF aqui, especificamente que você está compondo em vez de herdar (meu carro tem um motor vs. motor do meu carro é um WankelEngine). Eu gostaria de poder recordar a citação exatamente, mas é algo como "quebra de herança encapsulamento" e "composição favor sobre a herança".

Estou curioso que problema é resolvido por isso. Eu acho que você adicionou uma boa dose de complexidade e eu não estou vendo a necessidade de tal complexidade. Talvez seja algo específico para o idioma que eu não entendo.

Os caras GoF não discutir padrões que compõem em padrões maiores, MVC, em particular, é um agregado de três outros padrões. Parece que você já fez algo parecido.

Parece um pouco como Locator Service, em que os pesos penas são registrados como singletons.

O que você tem é um mapa, também conhecido como dicionário. Você apenas tem um único toque nele por ter várias chaves mapear para um objeto.

Por seu mapa a:

  • manter uma chave
  • Use a chave para consultar um valor de alguma estrutura de dados.

Você pode encontrar implementações em:

  • STL (incluem: mapa)
  • Java (importação: java.util.Dictionary)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top