É melhor Show () + Hide () ou SetVisible (bool visível)?

59

O que é melhor e por quê? (Do ponto de vista do design da interface):

a) Ter dois Show()e Hide()funções

b) Ter uma SetVisible(bool visible)função

EDIT: Por exemplo, algum objeto tem estado de visibilidade e esta função é usada para alterá-lo.

c) ter todos os três Show(), Hide(), SetVisible(bool visible)funções

user3123061
fonte
4
Em que contexto? Geralmente não importa
Aviv Cohn
6
Por que não tê-los todos públicos? Há casos em que você sabe que eles sempre serão mostrados ou ocultos e há casos em que você deseja mostrar ou ocultar condicionalmente.
pllee
@ pllee: Isso provavelmente é um ponto muito bom.
user3123061
4
Em java, seria setVisible, hide e show sem a letra maiúscula inicial.
Pierre Arlaud 21/03

Respostas:

81

Eu prefiro SetVisible(bool visible), porque me permite escrever o código do cliente assim:

SetVisible(DetermineIfItShouldBeVisible());

em vez de ter que escrever

if (DetermineIfItShouldBeVisible()) {
    Show();
} else {
    Hide();
}

A SetVisibleabordagem também pode permitir uma implementação mais fácil. Por exemplo, se uma classe concreta específica simplesmente delega o método para suas classes compostas, SetVisiblesignifica menos um método para implementar.

void ButtonWithALabel::SetVisible(bool visible) {
    myButton.SetVisible(visible);
    myLabel.SetVisible(visible);
}
Josh Kelley
fonte
25
Da mesma forma, você também pode tornar o Visible uma propriedade, desde que seu idioma seja compatível. MyObject.Visible = false;parece-me ainda mais intuitivo do queMyObject.SetVisible(false);
Brian
9
@ Brian Para mim, é menos legível e depurável, porque esconde o comportamento do programa aos meus olhos - a chamada do método subjacente -, mas isso é outra história. Java não suporta essa sintaxe, de qualquer forma, é uma questão de preferência e treinamento visual.
22414 ignis
10
SetVisible()não sugere (para mim) que você está realmente exibindo alguma coisa. Parece mais que você está configurando a propriedade de visibilidade de um objeto, possivelmente deixando para um método Refresh()ou correspondente Redisplay()para verificar o valor dessa propriedade para determinar se o objeto deve ser exibido ou oculto.
TMN
11
Infelizmente, o Java não suporta propriedades como o C #, apenas getters e setters que você vê acima.
theGreenCabbage 21/03
11
@TMN: Eu esperaria que, na ausência de outros fatores, a prevenção da visibilidade (ordem Z, visibilidade dos pais, localização etc.) setVisible(true)desencadeasse um processo em que o objeto seria desenhado quando o sistema estivesse ocioso, se não antes. Eu esperaria que refreshisso fosse útil para acelerar a exibição do objeto, mas que o objeto acabasse sendo desenhado independentemente (a menos que, por exemplo, sua visibilidade estivesse definida falseantes que isso ocorresse).
Supercat 23/03
35

Não concordo com todos os pôsteres que sugerem várias funções para fazer a mesma coisa. Enquanto três funções em vez de um pode não parecer muito inchaço, lembre-se que sua classe é provável que acabe com muitas dessas funções (por exemplo setEnabled, enable, disable) e, portanto, esta abordagem irá acabar com um muito interface da classe maior. Além disso, é provável que você acabe com várias funções / propriedades de som semelhantes / o que quer que seja da sua classe e a multiplicação de funções obscurecerá ainda mais qual delas combina com o quê.

Nas linguagens que suportam propriedades, essas devem ser preferidas, mas, como nem Java nem C ++, acho que esse é um ponto discutível.

Eu acho que setVisible()deveria ser preferido por estas razões:

  1. É imediatamente óbvio qual é a função inversa. Para inverter setVisible(false)você chama, setVisible(true)enquanto o oposto de hide()poderia ser facilmente reveal().
  2. É programaticamente mais simples sempre que você determina qual o estado que deve ter no código, ou seja, você pode chamar em setVisible(wantToSee)vez de usar uma ifinstrução.
  3. Depois de ter várias funções semelhantes, o setX()formato é generalizado, para que você possa ter um conjunto de funções consistentes, enquanto a abordagem com verbetes gera uma série de funções que podem ser difíceis de localizar se você não sabe o que está procurando. A consistência nas APIs as torna consideravelmente mais fáceis de aprender e lembrar.
Jack Aidley
fonte
3
O C ++ não possui propriedades, mas possui funções livres, para que você possa estender a interface da classe sem adicionar novas funções de membro, ou seja, com um menor grau de acoplamento.
Phresnel 21/03
O Qt geralmente fornece todos os três como uma conveniência, para que hide () e show () possam ser conectados diretamente a outros eventos usando o sistema de sinal / slot. Essa é realmente uma limitação do sistema de slots - se ele estivesse usando algo mais como funções boost ::, o argumento verdadeiro / falso poderia ser vinculado no momento de configurar o retorno de chamada.
11
"Em linguagens que suportam propriedades, essas devem ser preferidas, mas, como nem Java nem C ++, acho que esse é um ponto discutível". não necessariamente. Prefere getters / setters? Sim. Mas set_visible não é realmente um setter.
Route de milhas
19

Depende do que mostrar e ocultar significa no contexto. Primeiro, você deseja descobrir qual é o seu "caminho principal" e se concentrar em desenvolver isso:

  • Razões para escolher setVisible(bool)
    • É apenas um golpe de bit simples, ou seu objeto está principalmente mantendo o estado
    • Seu objeto passará a maior parte do tempo em uma estrutura CRUD
    • Existe muito código facilmente compartilhado entre mostrar e ocultar
  • Razões para escolher show()ehide()
    • Há efeitos colaterais importantes ou muita lógica sendo executada, como quando o objeto precisa verificar todos os seus contêineres quanto ao seu estado de visibilidade ou acionar uma animação de transição.
    • Faz parte de um modelo de domínio em que expressar intenção é importante

OK, agora que você codificou o núcleo "padrão ouro" dele, precisa descobrir se vale a pena adicionar métodos de conveniência finos no outro estilo, para facilitar a vida de quem vai usar seu objeto.

  • Conveniência de setVisible(bool)
    • Permite evitar declarações if que têm condições triviais e afetam apenas a visibilidade (ex. setVisible(a==b))
    • Pode ser conectado a certas estruturas getter / setter, se é algo que você espera que aconteça
  • Conveniência show()ehide()
    • Útil em um idioma com funções de primeira classe e retornos de chamada (ex. onSuccess(widget.show))
    • Muito mais fácil de ler com rastreamento de pilha e perfil de desempenho, pois você pode ver rapidamente o que o programa estava tentando fazer

TLDR: Descubra qual é o mais importante, implemente-o e, em seguida, pergunte-se se vale a pena adicionar o outro estilo como métodos de conveniência simples.

Darien
fonte
11

Eu diria "todos os três".

Show()e Hide()tendem a ser mais fáceis de grok do que SetVisible(true)e SetVisible(false). No entanto, quando você deseja definir visibilidade logicamente, é melhor ter um método usando um boolao invés de construir um em iftorno disso bool.

Você pode oferecer suporte aos três sem duplicar a lógica e o mínimo padrão:

void Show() {
    foo.Show();
    bar.Show();
}

void Hide() {
    foo.Hide();
    bar.Hide();
}

void SetVisible(bool visible) {
    if (visible) {
        Show();
    } else {
        Hide();
    }
}

Como alternativa, se as coisas que você está quebrando tiverem uma SetVisibleAPI mais -ish:

void Show() {
    SetVisible(true);
}

void Hide() {
    SetVisible(false);
}

void SetVisible(bool visible) {
    foo.SetVisible(visible);
    bar.SetVisible(visible);
}
Garry Shutler
fonte
40
A Microsoft usa essa abordagem para iniciar e parar System.Windows.Forms.Timer. Pessoalmente, acho isso confuso. Quando vejo ambos Showe SetVisible, minha primeira inclinação é pensar se há alguma diferença importante entre as duas funções.
Brian
11
Você pode documentá-los facilmente para eliminar essa confusão. Eu não fiz isso como um exemplo simples.
precisa
20
Então agora eu preciso gastar X minutos extras lendo a documentação antes de me sentir confortável usando a aula? Ou, alternativamente, preciso perder X minutos extras confusos (ou introduzindo bugs)? Claro, X é muito pequeno para esse tipo de coisa, mas definitivamente não é zero. Oferecer todas as três opções significa oferecer três vezes mais funções necessárias, o que significa que você gasta mais trabalho documentando e eu dedico mais trabalho aprendendo a usar a classe. Além disso, apresenta mais uma maneira de diferentes desenvolvedores serem inconsistentes ao usar sua classe.
20914 Brian
5
Essa é uma violação clara do princípio de Segregação de interface, um dos princípios do SOLID. Outra opinião contra a sua abordagem é a de jaroslav tulach, designer de netbeans, que insiste muitas vezes em fornecer apenas uma maneira de fazer uma coisa dentro de uma API em seu livro prático design de API.
AlfredoCasado
@AlfredoCasado Concordo. E se o SetVisible estivesse protegido ? Você poderia acessá-lo a partir de uma subclasse, mas a chamada para uma determinada entidade com essa interface (como uma API) teria que ser Ocultar / Mostrar.
Pierre Arlaud 21/03
5

Prefiro show () e hide (); de fato, todo método que recebe um booleano pode ser alterado por dois métodos, para expressar melhor a intenção da API. Por exemplo, Robert Martin em código limpo recomenda preferir métodos com zero argumentos sobre métodos com um argumento.

Outro argumento importante para mim é a legibilidade, na minha opinião, um bom código pode ser lido como prosa, é uma prosa realmente estranha algo como "main_window setVisible false" em vez de "main_window hide", você escreve ou fala assim normalmente ?, por que usar esse estranho construção de linguagem em programas de software quando é perfeitamente possível usar uma linguagem mais natural ?.

AlfredoCasado
fonte
11
A prosa do Assembler não é suficiente?
Alexander Alexander
Eu esperaria que a sequência it.setVisible(false); it.setVisible(true);não afetasse a visibilidade dos pais de um controle, nem a ordem Z ou o local do controle. Por outro lado hide(); show(),; plausivelmente, poderia forçar o pai de um controle a ficar visível, movê-lo acima de outros controles e limitar sua posição a um lugar que possa ser visto. Em alguns casos, é útil ter um meio de ter certeza que algo é realmente visível (como o já mencionado show(), mas em outros casos é útil para mudar a bandeira visibilidade sem alterar qualquer outra coisa.
supercat
Em uma API orientada a objetos, não há "sinalizadores", o OO é sobre mensagens, é sobre dizer a outro objeto para executar alguma tarefa, não sobre alterar "sinalizadores" que são o estado do objeto. Você está fazendo muitas suposições sobre controle, pais, ordenação z e o que espera com base provavelmente em sua experiência anterior com outras APIs, é uma péssima idéia projetar uma API com base em sentimentos e suposições pessoais sobre um domínio.
AlfredoCasado 24/03
5

Acredito que, quanto mais o método for expressivo, mais legível e, consequentemente, sustentável o código será. Considere os dois casos a seguir:

Caso 1:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  customerPanel.setVisible(customer.isCustomerEnabled());
}

Caso 2:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  //always show customer panel
  customerPanel.setVisible(true);
}

No primeiro caso, fica claro o que a função "setVisible" está fazendo, mas se você quiser lê-la, diria:

configure o painel do cliente para visível se o cliente estiver ativado ou oculto se o cliente estiver desativado.

Embora seja mais descritivo dizer:

  • verifique o status do cliente:
    • se o cliente estiver ativado, mostre o painel do cliente
    • caso contrário, esconda-o

que alterará a função "Caso 1" para o seguinte:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  if(customer.isCustomerEnabled()){
    customerPanel.Show();
  }
  else{
    customerPanel.Hide();
  }
}

produz mais código, mas é mais legível.

O segundo caso tem uma falha óbvia, ou seja, você já sabe que deseja mostrar o painel; então, por que não usar a função "Mostrar"?

Não estou dizendo que o uso de "setVisible" esteja absolutamente errado, mas fica confuso quando você tenta ler o código não escrito por você com o tempo e não está de acordo com a regra "A função deve executar apenas uma operação".

OKAN
fonte
Eu diria: show customer panel iff the user/customer is enabled. Concordo que pode haver muitas condições mais complexas que não são tão fáceis de ler quanto o seu exemplo; no entanto, nesses casos, eu as dividiria em linhas diferentes.
ComFreek
5

Acredito que a alternativa Hide()/ Show()seja atraente porque é mais fácil entender o que está acontecendo do que com SetVisible(true), embora seja preferível ter uma única função, pois evita muitos condicionais.

Se for esse o caso, sugiro usar uma enumeração como entrada para SetVisible, para que você obtenha um SetVisible(Visibility.Visible)ou outro SetVisible(Visibility.Hidden). Você tem uma única função e pode ler instantaneamente que ação está sendo executada.

Usando as convenções de nomenclatura de Java, você teria talvez setVisible(Visibility.VISIBLE)ou setVisible(Visibility.HIDDEN).

Gabe
fonte
3

Concordo com a resposta de Darien, mas queria acrescentar um ponto de vista da perspectiva de programadores em C #.

Quando vejo o código que diz 'setXXX', li que para dizer que está definindo um valor em uma coisa, não espero que isso tenha efeitos colaterais além de definir esse valor, e espero que seja idempotente (ou seja, posso continuar definindo-o com o mesmo valor e tudo bem). É como acessar um campo. Geralmente, eu também esperaria ver um método 'getXXX' junto com um 'setXXX'.

Não sei se é isso que você espera em Java e C ++, mas é o que eu esperaria em C #, embora em C # exista uma pequena mão para isso chamado Propriedades. E aqui estão algumas orientações interessantes sobre como usar as Propriedades ( http://msdn.microsoft.com/en-us/library/ms182181.aspx ).

Dada essa visão, a interface que eu escolheria depende apenas se houver algum efeito colateral (além de alterar esse valor do campo):

Se a execução da ação tiver efeitos colaterais, por exemplo, está mostrando uma caixa de diálogo, então eu usaria "Show ()" e "Hide ()".

Se não tiver efeitos colaterais, digamos que estou definindo a visibilidade de um "widget" e outra coisa renderize esse widget dependendo do estado, então eu usaria setVisibility ou setIsVisible. (Eu não chamaria SetVisible).

Em C # (não tenho certeza sobre Java), é bastante comum adotar um padrão de observador, em que uma estrutura de interface do usuário escuta alterações nos objetos e renderiza automaticamente a interface do usuário quando uma propriedade como Visibility é alterada. Isso significa que definir o valor chamando setIsVisible parece ter efeitos colaterais, mas, na minha definição, não. O contrato do widget é cumprido definindo seu valor de campo representando "IsVisible".

Em outras palavras, não há problema em alternar a visibilidade de um rótulo em um formulário antes que o formulário seja mostrado. Ou seja, label.getIsVisible == true, mas o formulário não é mostrado.

Não é legal chamar Hide () quando o formulário não está sendo mostrado.

Daniel James Bryars
fonte
11
Sua descrição getXXX()e setXXX()métodos como uma maneira de acessar um campo sem efeitos colaterais parecem Java e não C #. É assim que você deve fazê-lo em Java, porque ele não possui propriedades. Se eu vi um código como esse em C #, acho que foi escrito por um desenvolvedor Java que ainda não havia aprendido sobre propriedades em C #.
gilly3
+1 para SetVisibility.
akaltar
@ gilly3 - Sim, claro. E, "Propriedades" não existem no CLR, o C # se traduz nas chamadas de método get_XXX e set_YYY em IL. O que quero dizer é: no contexto da pergunta, se você viu setXXX, getXXX em Java, esperaria que funcionasse com a mesma semântica que as propriedades em C #. Sendo isso verdade, raciocino que as mesmas diretrizes para propriedades em C # são aplicáveis ​​aos pares de setXXX e getXXX em Java. Por acaso, concordo com as diretrizes mencionadas no post e, portanto, estou defendendo essas mesmas diretrizes para uso neste cenário em Java ao definir a interface.
precisa
11
Pode ajudar a esclarecer que, quando você quer dizer "efeitos colaterais", quer dizer "outros que não aqueles associados a ser algo" observável "". A regra que eu prefiro é dizer que, se uma getXXchamada tiver um setXXmétodo correspondente , setYYnão deverá afetá-la, mas poderá afetar uma getZZchamada que não possui um setZZmétodo.
Supercat 23/03
2

Eu sugeriria uma interface ligeiramente modificada:

Show();
Hide();
ToggleVisible();
ToggleVisible(bool visible);

Melhores nomes

Esses nomes de métodos ajudam o desenvolvedor a decidir qual método usar, com base no que precisa ser feito. Considerando que SetVisible(bool visible)pode confundir um desenvolvedor porque ele transmite o mesmo significado semântico que Show()e Hide(), Toggle()implica a existência de uma condição que determina a ação. Assim, torna-se intuitivo para o desenvolvedor quando usar cada método.

Redundância de código reduzida

O benefício de ter vários métodos em sua interface é que simplifica o código de chamada. Você pode apenas expor Show()e Hide(), mas:

  • Você provavelmente exigiria algum tipo de SetVisible()método privado para fazer o trabalho real nos bastidores (ou escrever código redundante para Show()e Hide()).
  • O código de chamada pode ter muitos blocos redundantes se / else apenas para escolher qual método usar. Isso incha o código na minha opinião.
  • Se eu fosse o consumidor, provavelmente escreveria minha própria função de wrapper que faz o que SetVisible()(ou Toggle()) já faz para evitar o inchaço do código (eu odeio código redundante). Assim, duplicar um método que provavelmente já existe como método privado na implementação.
gilly3
fonte
11
A duplicação do método parece razoável, apesar de eu não fazer isso sozinho. Por outro lado, não concordo que toggleVisible (bool) seja intuitivo. Para mim, isso significa que deve alternar se o bool passado for verdadeiro, o que seria bastante estranho, mas eu já vi um estranho. Não presumiria que é realmente uma função definida disfarçada.
Patrick M
0

Eu sugeriria que use SetVisible(bool)if if only, se alternar a visibilidade duas vezes (mostrar e re-ocultar, ou ocultar e re-mostrar) deixaria as coisas essencialmente no mesmo estado de antes da operação (é bom se mostrar e ocultar algo ou vice-versa deixa os objetos precisando de um redesenho, desde que se possa esperar que ocorra "automaticamente"). Se ocultar e mostrar um objeto não tiver outro efeito além de alterar um bit de estado, faria sentido para o código externo ter alguns métodos que aceitem um parâmetro de visibilidade, e a gravação desse código será facilitada SetVisible.

Se ocultar e mostrar novamente um objeto pode ter efeitos colaterais, como alterar a ordem Z, é mais provável que essas ações sejam executadas por métodos separados. Nesses casos, a utilidade de métodos externos que aceitam um parâmetro de "visibilidade" será limitada e, portanto, haverá pouca vantagem em facilitá-los. Além disso, um SetVisiblemétodo (erroneamente) sugere que alterações na visibilidade dos objetos podem ser realizadas sem efeitos colaterais.

supercat
fonte