Três classes e métodos get

5
class A{
    private List<T> list;

    public int getListSize(){
        return list.size();
    }
}

class B{
    private A objectA;

    public int getSizeOfListInA{
        return objectA.getListSize();
    }


}

class C{
    B objectB;
    // here I need to know the size of the list 
}

Estou simplificando demais aqui, mas fiquei me perguntando se essa é a maneira correta de escrever o código correto - suponha que a classe C precise saber o tamanho da lista. Se houvesse outra classe D mantendo o objeto da classe C nela, e D quisesse saber o tamanho da lista de A, eu precisaria de outro método getSizeOfTheList na classe C. Então, é muita duplicação de código - três métodos que geralmente fazem a mesma coisa, simplesmente porque uma classe que está no nível acima quer saber suas coisas internas. É claro que seria melhor se C não precisasse saber o tamanho da lista, mas às vezes faz sentido.

Editar:

Se A fosse uma classe imutável, então seria melhor ter getObjectA na classe B? Suponha que eu queira disponibilizar todos os métodos objectA para os clientes da classe B - incluindo o método getObjectA Eu não preciso reescrever cada um deles em B. O cliente simplesmente chama primeiro getObjectA e depois chama seu método.

A questão é, obviamente, se eu realmente quero que os clientes acessem todos os métodos de A. E seria mais difícil para os clientes de B usarem minha API. Então, eu ou meus clientes teremos vida mais fácil.

    
por user4205580 05.04.2016 / 12:17
fonte

1 resposta

8

Você tem razão em não ter certeza sobre isso, já que às vezes isso é perfeitamente correto e, às vezes, indica falha no projeto.

A chave para procurar é se essa "mesmice" é apenas uma propriedade acidental das implementações, ou uma necessidade imposta pelos contratos de métodos (implícitos) . O primeiro é bom, enquanto o segundo indica redundância séria.

Por exemplo, aqui está um caso em que provavelmente é aceitável:

// this class is part of the database implementation used for SELECT queries
class ReadOnlyDatabaseRowImplList implements DatabaseRowImplList {
    private List<DatabaseRowImpl> rows;
    public int getRowCount() { return rows.size(); }
    // other methods
}

// this class is what the database returns to the microservice for any type of query
class QueryResult {
    private DatabaseRowImplList rows;
    public int numRowsAffected() { return rows.size(); }
    // other methods
}

// this class is what the microservice returns to the client
class CompanyEarningsHistory {
    private QueryResult earnings;
    public int yearsWithHistoryAvailable() { return earnings.numRowsAffected(); }
    // other methods
}

Os três métodos têm implementações (quase) idênticas, mas a semântica é diferente em cada nível, e o usuário de cada método não sabe nem se importa se a implementação é "apenas um passo a passo" ou não. É inteiramente possível que um desses métodos possa mudar no futuro para ter uma lógica mais interessante, mantendo seus contratos implícitos.

Mas se você se encontrar escrevendo algo assim:

class FooWrapper {
    private Foo foo;

    // returns the current value of the bar member on this class' internal foo object
    public SomeType getFooDotBar() {
        return foo.bar;
    }
}

Então é muito provável que você tenha cometido um erro em algum lugar. Idealmente, veja se você pode descobrir por que FooWrapper usuários acham que precisam de getFooDotBar() e criar uma maneira de incorporar esse recurso / solução alternativa à "parte limpa" de sua API. Em alguns casos raros, seus usuários realmente precisarão de acesso direto a um dos objetos que você está envolvendo, caso em que você deve expor todo o objeto Foo diretamente, ou talvez um wrapper somente de leitura (veja métodos como Collections.unmodifiableList() ) .

    
por 05.04.2016 / 12:51
fonte