Setters e getters sempre quebram o Princípio de Responsabilidade Única?

8

Como sabemos, o SRP declara que toda classe deve ter responsabilidade única e essa responsabilidade deve ser totalmente encapsulada pela classe.

Mas setters e getters cumprem outra responsabilidade - eles fazem acesso à propriedade de classe abstrata (dados).

se Setters e getters fazem acesso à propriedade de classe abstrata, eles servem outra responsabilidade .

Então, se eu tenho algo assim,

class Config
{

    private location;


    public function write(array $data)
    {
        ....
    }

    public function read($key)
    {
        ...
    }

    public function exists($key)
    {
        ...
    }

    public function delete($key)
    {
        ...
    }

    // Below comes property abstraction

    // Here I doubt - I CANNOT USE this class without them
    // but they seem to break the SRP at the same time!?

    public function setFileLocation($location)
    {
        $this->location = $location;
    }


    public function getFileLocation()
    {
        return $this->location;
    }


    public function setConfigArray(...)
    {
        ...
    }

    public function getConfigArray()
    {
        ...
    }
}

Eu quebro o SRP. O problema é que essa é a única maneira de existir a classe.

Então a questão é:

Na minha situação, é quase impossível evitar métodos setFileLocation()e getFileLocation()métodos CRUD.

Portanto, se combinando métodos CRUD com abstração de acesso a dados eu quebro o SRP,

Existe alguma maneira de aderir ao SRP e manter o conceito comum da classe Config (operações CRUD) ao mesmo tempo?

Yang
fonte
1
@metal_fan: Você quebra exatamente a mesma funcionalidade se tiver um membro público ou se tiver um membro privado com getter e setter públicos triviais. E digo exatamente isso porque pode não haver nenhum em alguns casos e tudo em outros. Dependendo se o uso deles pode quebrar invariantes internos.
Jan Hudec
1
Qual é a responsabilidade da classe de configuração se não for para fornecer um local centralizado para armazenar e recuperar esses valores de configuração? O SRP está quebrado em todos os bancos de dados? No exemplo em que você vincula, há duas responsabilidades: 1 são getters e setters, 2 é CRUD. No exemplo que você postou, não há CRUD, portanto, há apenas 1 responsabilidade.
Trylks
" Você confundiu o verdadeiro e o real. " - George Stanley na conversa, citado por Samuel R Delany

Respostas:

11

Honestamente, acho que você está levando o conceito de responsabilidade única um pouco longe demais. Os getters e setters são incidentais ao funcionamento da classe, seja por acesso direto a membros públicos ou por métodos (ou propriedades) para fazê-lo.

Você está argumentando que conseguir e definir algum membro da classe é uma responsabilidade separada e, portanto, deve ser movido para outro lugar. Digamos que fazemos isso, e agora você tem as classes chamadas Confige ConfigAccessor. Neste ponto, agora você tem um espaço de ar entre as duas classes, porque Confignão possui interface para acessar seu locationmembro. Isso torna impossível escrever ConfigAccessor, e você fica com uma classe imutável de escrever uma vez que não tem qualquer utilidade. Se você adicionar algum tipo de interface para permitir ConfigAccessorque ele faça seu trabalho, você se encontrará com um problema recursivo.

O SRP, como muitas outras coisas neste campo, é um princípio, não uma regra rígida. Isso significa que você deve aplicar julgamento à sua situação em vez de tentar segui-la incondicionalmente. Há uma linha entre ser um purista e fazer o trabalho, e quando o primeiro está impedindo o segundo, você está do lado errado.

Se posso criticar um pouco seu design: se sua Configclasse foi projetada para ser uma interface entre um arquivo de configuração armazenado em disco e seu código, a última coisa que você deseja fazer é mudar sua localização no meio do caminho. Se você estiver alterando a locationforma de iniciar o acesso a um arquivo diferente, destrua o objeto antigo e crie um novo. Você não deixou claro se pretende armazenar o conteúdo do arquivo no objeto. Se você planejou usá-lo como uma maneira de inalar o conteúdo de um arquivo de configuração e gravá-lo em outro, considere usar um método que clone os dados em um novo objeto que aponte para o novo arquivo.

Blrfl
fonte
4

Existem dois níveis distintos nos quais você pode aplicar o SRP.

O primeiro nível é o nível de funções / métodos individuais. Cada um deve executar apenas uma tarefa (e, a julgar pelos nomes dos métodos, nenhum dos métodos de Configquebrar o SRP).

O segundo nível é o nível de uma classe. Aqui, o conceito de uma única responsabilidade se torna um pouco mais abstrato, mas um bom indicador é se você pode declarar as responsabilidades de uma classe em uma frase sem o uso (implícito) da palavra e . Se você puder fazer isso com a presença de getters e setters, a classe não interromperá o SRP.

Em geral, getters e, em menor grau, setters são , no entanto, uma indicação de que o encapsulamento de uma classe está quebrado. No caso da Configclasse, o setFileLocationmétodo é bom, pois Configprecisa de alguma maneira de saber onde os dados estão localizados, mas os outros parecem suspeitos, porque expõem informações das quais os usuários Confignão precisam.

Bart van Ingen Schenau
fonte
4

Sua classe de configuração tem a responsabilidade de rastrear a configuração, que é implementada mantendo referências particulares a determinados dados e fornecendo acesso a eles por meio de métodos mutadores. Isso não quebra o SRP, porque a própria classe ainda tem uma única responsabilidade ; os mutadores simplesmente ajudam a cumprir essa responsabilidade abstraindo o acesso aos dados. Os mutadores não têm uma responsabilidade separada da da classe; eles fazem parte da maior responsabilidade da classe.

Mike Partridge
fonte