fundo
Atualmente, tenho uma situação em que tenho um objeto que é transmitido e recebido por um dispositivo. Esta mensagem possui várias construções, da seguinte maneira:
public void ReverseData()
public void ScheduleTransmission()
O ScheduleTransmission
método precisa chamar o ReverseData
método sempre que for chamado. No entanto, há momentos em que precisarei chamar ReverseData
externamente (e devo adicionar completamente fora do namespace ) de onde o objeto é instanciado no aplicativo.
Quanto ao "recebimento", quero dizer que ReverseData
será chamado externamente em um object_received
manipulador de eventos para reverter os dados.
Questão
É geralmente aceitável que um objeto chame seus próprios métodos públicos?
Respostas:
Eu diria que não é apenas aceitável, mas incentivado, especialmente se você planeja permitir extensões. Para oferecer suporte a extensões da classe em C #, você precisa sinalizar o método como virtual, de acordo com os comentários abaixo. Você pode documentar isso, no entanto, para que alguém não fique surpreso ao substituir ReverseData () altera a maneira como ScheduleTransmission () funciona.
Realmente se resume ao design da classe. ReverseData () parece um comportamento fundamental da sua classe. Se você precisar usar esse comportamento em outros lugares, provavelmente não deseja ter outras versões. Você só precisa ter cuidado para não permitir que detalhes específicos de ScheduleTransmission () vazem para ReverseData (). Isso criará problemas. Mas como você já está usando isso fora da classe, provavelmente já pensou nisso.
fonte
ReverseData()
seja abstrato, não importa o que você faça na classe filho, é sempre o método original que será chamado.virtual
... E se você está substituindo o método, por definição, ele precisa servirtual
ouabstract
.virtual
também funciona. Em todos os casos, a assinatura, de acordo com o OP, épublic void ReverseData()
, portanto, a parte da resposta sobre substituir coisas é um pouco enganadora.abstract
? Procurei respostas noabstract
vsvirtual
e não vi o mencionado: bastante abstrato significa apenas que não há versão dada nesta base.Absolutamente.
A visibilidade de um método tem como único objetivo permitir ou negar acesso a um método fora da classe ou dentro de uma classe filho; métodos públicos, protegidos e privados sempre podem ser chamados dentro da própria classe.
Não há nada errado em chamar métodos públicos. A ilustração na sua pergunta é o exemplo perfeito de uma situação em que ter dois métodos públicos é exatamente o que você deve fazer.
No entanto, você pode observar cuidadosamente os seguintes padrões:
Um método
Hello()
chamaWorld(string, int, int)
assim:Evite esse padrão. Em vez disso, use argumentos opcionais . Argumentos opcionais facilitam a descoberta: o chamador que digita
Hello(
não necessariamente sabe que existe um método que possibilita chamar o método com valores padrão. Argumentos opcionais também são auto-documentados.World()
não mostra ao chamador quais são os valores padrão reais.Um método
Hello(ComplexEntity)
chamaWorld(string, int, int)
assim:Em vez disso, use sobrecargas . Mesmo motivo: melhor descoberta. O chamador pode ver imediatamente todas as sobrecargas através do IntelliSense e escolher a correta.
Um método simplesmente chama outros métodos públicos sem agregar nenhum valor substancial.
Pense duas vezes. Você realmente precisa deste método? Ou você deve removê-lo e permitir que o chamador invoque os diferentes métodos? Uma dica: se o nome do método não parecer correto ou difícil de encontrar, você provavelmente deverá removê-lo.
Um método valida a entrada e chama o outro método:
Em vez disso,
World
deve validar seus próprios parâmetros ou ser privado.fonte
Se algo é público, pode ser chamado a qualquer momento por qualquer sistema. Não há razão para que você também não possa ser um desses sistemas!
Em bibliotecas altamente otimizadas, você deseja copiar o idioma apresentado
java.util.ArrayList#ensureCapacity(int)
.garantirCapacidade
ensureCapacity
é públicoensureCapacity
tem todos os limites necessários de verificação e valores padrão, etc.ensureCapacity
chamadasensureExplicitCapacity
asseguraCapacityInternal
ensureCapacityInternal
é privadoensureCapacityInternal
possui verificação mínima de erros, porque todas as entradas vêm de dentro da classeensureCapacityInternal
TAMBÉM chamaensureExplicitCapacity
assegureCapacidadeExplicita
ensureExplicitCapacity
também é privadoensureExplicitCapacity
não tem verificação de erroensureExplicitCapacity
faz trabalho realensureExplicitCapacity
não é chamado de qualquer lugar, exceto porensureCapacity
eensureCapacityInternal
Dessa maneira, o código em que você confia obtém acesso privilegiado (e mais rápido!) Porque você sabe que suas entradas são boas. O código no qual você não confia passa por um certo rigor para verificar sua integridade e bomba, fornecer padrões ou manipular informações incorretas. Ambos canalizam para o local que realmente funciona.
No entanto, isso é usado no ArrayList, uma das classes mais usadas no JDK. É muito possível que seu caso não exija esse nível de complexidade e rigor. Para encurtar a história, se todas as
ensureCapacityInternal
chamadas fossem substituídas porensureCapacity
chamadas, o desempenho ainda seria muito, muito bom. Esta é uma microoptimização provavelmente feita apenas após uma análise extensiva.fonte
Várias boas respostas já foram dadas, e eu também concordaria com elas que sim, um objeto pode chamar seus métodos públicos de outros métodos. No entanto, há uma pequena ressalva de design que você terá que observar.
Os métodos públicos geralmente têm um contrato de "levar o objeto em um estado consistente, fazer algo sensato, deixar o objeto em um estado consistente (possivelmente diferente)". Aqui, "consistente" pode significar, por exemplo, que o
Length
de aList<T>
não é maior que o seuCapacity
e que a referência aos elementos nos índices de0
paraLength-1
não será lançada.Mas, dentro dos métodos do objeto, o objeto pode estar em um estado inconsistente; portanto, quando você chama um de seus métodos públicos, pode fazer uma coisa muito errada, porque não foi escrito com essa possibilidade em mente. Portanto, se você planeja chamar seus métodos públicos de outros métodos, verifique se o contrato deles é "pegue o objeto em algum estado, faça algo sensato, deixe o objeto em um (possivelmente diferente) (talvez inconsistente - mas apenas se o estado inconsistente) ".
fonte
Outro exemplo ao chamar método público dentro de outro método público é totalmente adequado é uma abordagem CanExecute / Execute. Eu o uso quando preciso de validação e preservação invariável .
Mas, em geral, sou sempre cauteloso com isso. Se um método
a()
é chamado de método internob()
, significa que esse métodoa()
é um detalhe de implementaçãob()
. Muitas vezes, indica que eles pertencem a diferentes níveis de abstração. E o fato de ambos serem públicos me faz pensar se é uma violação do princípio de responsabilidade única ou não.fonte
Desculpe, mas vou ter que discordar da maioria das outras respostas 'sim, você pode' e dizer o seguinte:
Eu desencorajaria uma classe chamando um método público de outro
Existem alguns problemas em potencial com essa prática.
1: Loop infinito na classe herdada
Portanto, sua classe base chama method1 do method2, mas você ou outra pessoa herda dele e oculta o method1 com um novo método que chama method2.
2: Eventos, registro etc.
por exemplo, eu tenho um método Add1 que dispara um evento '1 added!' Eu provavelmente não quero que o método Add10 levante esse evento, grave em um log ou o que seja, dez vezes.
3: rosqueamento e outros impasses
Por exemplo, InsertComplexData abre uma conexão db, inicia uma transação, bloqueia uma tabela e chama InsertSimpleData, com abre uma conexão, inicia uma transação, aguarda que a tabela seja desbloqueada ....
Tenho certeza de que há mais motivos, uma das outras respostas foi tocada em 'você edita o método1 e fica surpreso com o método2 começa a se comportar de maneira diferente'
Geralmente, se você tem dois métodos públicos que compartilham código, é melhor fazê-los chamar um método privado em vez de um chamar o outro.
Editar ----
Vamos expandir o caso específico no OP.
não temos muitos detalhes, mas sabemos que ReverseData é chamado por algum manipulador de eventos, bem como o método ScheduleTransmission.
Suponho que os dados reversos também alterem o estado interno do objeto
Dado este caso, eu pensaria que a segurança do thread seria importante e, portanto, minha terceira objeção à prática se aplica.
Para tornar o thread ReverseData seguro, você pode adicionar um bloqueio. Mas se o ScheduleTransmission também precisar ser seguro para threads, você desejará compartilhar o mesmo bloqueio.
A maneira mais fácil de fazer isso é mover o código ReverseData para um método privado e fazer com que ambos os métodos públicos o chamem. Você pode colocar a instrução lock nos Métodos Públicos e compartilhar um objeto de bloqueio.
Obviamente, você pode argumentar "isso nunca vai acontecer!" ou "Eu poderia programar o bloqueio de outra maneira", mas o ponto sobre as boas práticas de codificação é estruturar bem seu código em primeiro lugar.
Em termos acadêmicos, eu diria que isso viola o L em sólido. Os métodos públicos são mais do que acessíveis publicamente. Eles também são modificáveis por seus herdeiros. Seu código deve ser fechado para modificação, o que significa que você precisa pensar no trabalho que realiza nos métodos público e protegido.
Aqui está outra: você também potencialmente viola o DDD. Se seu objeto é um objeto de domínio, seus métodos públicos devem ser termos de domínio, que significam algo para os negócios. Nesse caso, é muito improvável que "compre uma dúzia de ovos" seja o mesmo que "compre 1 ovo 12 vezes", mesmo que comece dessa maneira.
fonte