Eu acho que o título "Método sinalizadores como argumentos ou como variáveis de membro?" pode ser subótimo, mas como estou perdendo uma terminologia melhor, aqui vai:
Atualmente, estou tentando entender o problema de saber se os sinalizadores para um determinado método de classe ( privado ) devem ser passados como argumentos de função ou via variável de membro e / ou se existe algum padrão ou nome que cubra esse aspecto e / ou se isso sugere alguns outros problemas de design.
Por exemplo (a linguagem pode ser C ++, Java, C #, realmente não importa IMHO):
class Thingamajig {
private ResultType DoInternalStuff(FlagType calcSelect) {
ResultType res;
for (... some loop condition ...) {
...
if (calcSelect == typeA) {
...
} else if (calcSelect == typeX) {
...
} else if ...
}
...
return res;
}
private void InteralStuffInvoker(FlagType calcSelect) {
...
DoInternalStuff(calcSelect);
...
}
public void DoThisStuff() {
... some code ...
InternalStuffInvoker(typeA);
... some more code ...
}
public ResultType DoThatStuff() {
... some code ...
ResultType x = DoInternalStuff(typeX);
... some more code ... further process x ...
return x;
}
}
O que vemos acima é que o método InternalStuffInvoker
usa um argumento que não é usado dentro dessa função, mas é encaminhado apenas para o outro método privado DoInternalStuff
. (Onde DoInternalStuff
será usado em particular em outros lugares desta classe, por exemplo, no DoThatStuff
método (público).)
Uma solução alternativa seria adicionar uma variável de membro que carregasse essas informações:
class Thingamajig {
private ResultType DoInternalStuff() {
ResultType res;
for (... some loop condition ...) {
...
if (m_calcSelect == typeA) {
...
} ...
}
...
return res;
}
private void InteralStuffInvoker() {
...
DoInternalStuff();
...
}
public void DoThisStuff() {
... some code ...
m_calcSelect = typeA;
InternalStuffInvoker();
... some more code ...
}
public ResultType DoThatStuff() {
... some code ...
m_calcSelect = typeX;
ResultType x = DoInternalStuff();
... some more code ... further process x ...
return x;
}
}
Especialmente para cadeias de chamadas profundas em que o sinalizador seletor para o método interno é selecionado fora, o uso de uma variável de membro pode tornar as funções intermediárias mais limpas, pois elas não precisam carregar um parâmetro de passagem.
Por outro lado, essa variável de membro não está realmente representando nenhum estado do objeto (como não está definida nem disponível fora), mas é realmente um argumento adicional oculto para o método privado "interno".
Quais são os prós e os contras de cada abordagem?
fonte
Respostas:
Isso reforça minha intuição ao ler sua pergunta: tente manter esses dados o mais local possível, ou seja, não os adicione ao estado do objeto . Isso reduz o espaço de estado da sua classe, tornando seu código mais simples de entender, testar e manter. Sem mencionar que evitar o estado compartilhado também torna sua classe mais segura - isso pode ou não ser uma preocupação para você agora, mas pode fazer uma enorme diferença no futuro.
Obviamente, se você precisar passar excessivamente por essas bandeiras, isso pode se tornar um incômodo. Nesse caso, você pode considerar
fonte
Eu definitivamente votaria na opção "argumento" - minhas razões:
Sincronização - e se o método for chamado de vários threads ao mesmo tempo? Ao passar os sinalizadores como argumento, você não precisará sincronizar o acesso a esses sinalizadores.
Testabilidade - Vamos imaginar que você está escrevendo um teste de unidade para sua classe. Como você testará o estado interno do membro? E se o seu código lançar uma exceção e o membro terminar em um estado inesperado?
Separação de preocupações - Ao adicionar as sinalizações aos argumentos do método, fica claro que nenhum outro método deve usá-lo. Você não o utilizará por engano em outro método.
fonte
A primeira alternativa parece boa para mim. Uma função é chamada com um parâmetro e faz algo que depende desse parâmetro . Mesmo se você apenas encaminhar o parâmetro para outra função, espera que o resultado dependa de alguma forma do parâmetro.
A segunda alternativa parece usar uma variável global, apenas dentro do escopo da classe, em vez do escopo do aplicativo. Mas é o mesmo problema ... você deve ler atentamente todo o código da classe para determinar quem e quando está lendo e gravando esses valores.
Portanto, a primeira alternativa vence.
Se você usar muitos parâmetros (leia-se: dois ou mais) na primeira alternativa, todos passados juntos para a próxima função, considere colocá-los em um único objeto (torne-o uma classe interna, se não for relevante para o restante do aplicativo) e usando esse objeto como parâmetro.
fonte
Eu quero dizer "nenhum".
Primeiro, considere que você já sabe o que fará quando ligar
DoInternalStuff
. A bandeira diz o mesmo. Então agora, em vez de seguir em frente e fazê- lo, você está peidando ao chamar uma função que agora precisa decidir o que fazer.Se você quiser dizer à função o que fazer, diga-lhe o que fazer . Você pode passar uma função real que deseja executar para cada iteração como um representante de C # (ou um objeto de função C ++, ou um executável em Java ou semelhante).
Em c #:
Você ainda acaba com o argumento passando por todo o lado, mas se livra da maior parte da porcaria de if / else
DoInternalStuff
. Você também pode armazenar o delegado como um campo, se desejar.Quanto a distribuir ou armazenar a coisa toda ... se você tiver que escolher uma, passe-a por aí. Armazená-lo provavelmente irá morder sua bunda mais tarde, pois você praticamente negligenciou a segurança do thread. Considere que, se você pretende fazer algo com threads, agora precisa bloquear por toda a duração do loop, ou alguém pode alternar as tarefas de baixo de você. Considerando que, se você passar, é menos provável que seja destruído ... e se você ainda precisar bloquear ou algo assim, poderá fazê-lo por parte de uma iteração em vez de todo o loop.
Francamente, é bom que seja irritante. Provavelmente existe uma maneira muito mais simples de fazer o que você quer, o que eu realmente não poderia aconselhá-lo, já que o código obviamente não é a coisa real. A melhor resposta varia de acordo com o caso.
fonte