Pergunta

Estou criando uma biblioteca de classe com muitas opções diferentes para personalizações possíveis. Por exemplo, você pode projetar sua classe para que ele possa realizar FeatureX (), ou você pode criar sua classe para que ele possa realizar FeatureY ().

Em circunstâncias normais, você poderia simplesmente criar uma interface IFeatureX com um método virtual puro chamado FeatureX, e outra interface IFeatureY com um método virtual puro chamado FeatureY. Se uma classe tem tanto FeatureX e FeatureY, ele pode herdar de ambos, não há problema.

O meu problema é, o que se uma função / método requer um objeto que pode executar tanto FeatureX () e FeatureY ()? Como faço para expressar um tipo, em C ++ preferência, mas uma resposta em Java poderia ajudar também, para assegurar que tanto FeatureX e FeatureY estão disponíveis?

faço para criar outra interface IFeatureXY que herda de IFeatureX e IFeatureY? Ok ... se há apenas duas características que eu poderia ir longe com isso. Mas se houver digamos ... 10 características, o número de interfaces possíveis torna-se enorme.

Existe uma maneira simples de fazer isso? Eu tentei resolver o problema usando modelos e delegação C ++, mas não chegar muito longe. Eu estou esperando há uma solução simples para isso, e provavelmente é um que eu apenas esquecido.

Agradeço qualquer ajuda e conselhos que vocês têm.

Graças.

Foi útil?

Solução

Se você não tem medo de usar modelos, você pode fazer a sua função de um modelo e usar SFINAE para verificar se as duas interfaces:

template <class T>
void my_function(const T& data, typename enable_if_c<
    is_convertible<T*, IFeatureX*>::value && 
    is_convertible<T*, IFeatureY*>::value>::type*=0) {
  ...
}

Isto irá criar um método para cada tipo que estende ambas as interfaces recurso (note que o truque SFINAE não é necessário para que ele funcione; um modelo sem restrições iria funcionar, mas apenas não compilar quando você passa um tipo que não faz atender aos requisitos).

Outra possibilidade é criar uma interface IFeatureXY estendendo ambos, e usar isso em parâmetros da função; isto tem a desvantagem de que tipos que fazer implementar ambas as interfaces, mas não esta interface comum não seria utilizável com este método.

Além disso, você pode passar dois argumentos para a função, um por interface, e exigem que eles são ponteiros para o mesmo objeto; este é frágil, mas pode ser endurecido, fazendo alguma classe de modelo para manter os dois ponteiros - por exemplo. product_type<IFeatureX*, IFeatureY*>, que seria inicializado pelo único objeto em questão e que iria realizar os dois tipos.

Em Java, você provavelmente poderia fazer a mesma coisa com as variáveis ??do tipo limitados (se eles permitem que vários limites, eu não tenho certeza agora).

Outras dicas

A primeira coisa a fazer é perguntar se você está tentando fazer algo que não pode ser expresso de forma simples, e se assim for, pergunte-se se é realmente vale a pena fazer?

Uma vez que você não consegue encontrar um modelo mais simples do que você quer, você está indo para necessidade de pensar sobre dependências entre as opções. Se você pode usar o recurso X independentemente do recurso Y, em seguida, fazê-los de interfaces independentes ou aulas virtuais puros (conforme apropriado para a linguagem.)

Se você não pode usá-los de forma independente, fazer uma classe que inclui tanto; perguntar por que você quer FeatureX e FeatureY como interfaces separadas, porque esse padrão de uso sugere que eles não são independentes depois de tudo.

Embora existam maneiras de adicionar características completamente diferentes, que você pode querer pensar sobre o alcance desses recursos adicionais. eles vão estar relacionado com a sua biblioteca de classe principal? (Alguém poderia argumentar que, se não forem eles não devem ser parte dela)

Se eles têm o suficiente em comum com mandado de adição de recursos que você pode olhar para algo como o padrão de decorador ( http : //en.wikipedia.org/wiki/Decorator_pattern ). Ele permite que você ignorar algumas das questões vacilante com fazer as coisas como esta.

Se você quiser ot fazê-lo em c ++, o que acontece com herança múltipla?

Possivelmente você está sendo muito fina granulação. Considere uma classe numérico - você pode executar multiplicação, divisão, adição, subtração, etc. No entanto, você não iria criar interfaces separadas para cada uma dessas operações - você criaria uma interface chamada SupportsArithmetic (ou qualquer outro) que todos eles cobertos

WCF tem padrão muito bom como determinar se algum objeto suporta alguma interface (ou classe) utilizando IExtensionCollection<T>.Find<E>(). IExtensionCollection .

IFeatureX feature = argument.Find<IFeatureX>();

if (feature != null)
{
    // Find() returned an instance so there is an implementation
    // of IFeatureX available

   feature.FeatureX();
}

Desta forma, você pode consultar o seu objeto por algum inteface. Um método semelhante é usado em COM + em IUnknown :: QueryInterface ( ) .

Por que você precisa de interfaces? Use modelos:

template< typename T >
void some_function( const T& t )
{
    // use featureX functions
    t.fetatureX();

    // use featureY functions
    t.featureY();
}

Uso:

SomeClass x; // object with only X feature
some_function( x ); // compile time error, because featureY() doesn't exists
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top