より良いShow()+ Hide()またはSetVisible(bool visible)ですか?


59

何が良くて、なぜですか?(インターフェース設計の観点から):

A)2持っているShow()Hide()機能を

b)1つのSetVisible(bool visible)機能を持つ

編集:たとえば、一部のオブジェクトには可視性の状態があり、この関数を使用して変更します。

C)3つのすべての持っているためにShow()Hide()SetVisible(bool visible)機能を


4
どのような文脈で?一般的に、それは問題ではありません
テルアビブコーン


6
それらをすべて公開しないのはなぜですか?常に表示または非表示になることがわかっている場合と、条件付きで表示または非表示にする場合があります。
嘆願

@pllee:それはおそらく非常に良い点です。
user3123061 14年

4
Javaでは、setVisible、hide、showを大文字の大文字なしで行います。
ピエールアラード14年

回答:


81

次のSetVisible(bool visible)ようなクライアントコードを記述できるため、

SetVisible(DetermineIfItShouldBeVisible());

書く代わりに

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

このSetVisibleアプローチにより、実装が容易になる場合もあります。たとえば、特定の具象クラスが単にメソッドをその複合クラスに委任する場合、SetVisible実装するメソッドが1つ少なくなります。

void ButtonWithALabel::SetVisible(bool visible) {
    myButton.SetVisible(visible);
    myLabel.SetVisible(visible);
}

25
同様に、Visibleをプロパティにすることもできます(言語がサポートしている場合)。 MyObject.Visible = false;より直感的であるように感じますMyObject.SetVisible(false);
ブライアン14年

9
@Brian私にとっては、プログラムの振る舞い-基礎となるメソッド呼び出し-を隠しているため、読みにくくデバッグしにくいですが、それは別の話です。Javaは、その構文をサポートしていません。とにかく、好みと視線の問題です。
イグニス14年

10
SetVisible()実際に何かを表示していることを(私には)示唆していません。オブジェクトの可視性プロパティを設定しているように見えますが、対応するメソッドRefresh()Redisplay()メソッドに任せて、このプロパティの値をチェックして、オブジェクトを表示するか非表示にするかを決定します。
TMN 14年

1
残念ながら、JavaはC#のようなプロパティをサポートせず、上記のゲッターとセッターのみをサポートします。
theGreenCabbage 14年

1
@TMN:可視性を妨げる他の要因(Zオーダー、親の可視性、場所など)setVisible(true)がないと、システムが次にアイドル状態になったときにオブジェクトが描画されるプロセスが動き始めます。私はそれrefreshがオブジェクトの表示を早めるのに役立つかもしれないと期待しますが、オブジェクトは最終的には関係なく描画されます(例えば、その可視性がfalse発生する前に設定されていない限り)。
supercat

35

同じことをするために複数の機能が良いことを示唆しているすべてのポスターに同意しません。代わりに、1の三つの機能が大幅に肥大化のように見えるではないかもしれないが、あなたのクラスは、このような多くの機能(例えばで終わる可能性があることを覚えてsetEnabledenabledisableとなってしまいます)ので、このアプローチもはるかに大きいクラスインターフェイス。さらに、クラス内で似たような音の関数/プロパティ/何でもできてしまい、関数の乗算により、どちらがどのようになるかがさらにわかりにくくなる可能性があります。

プロパティをサポートする言語では、これらを優先する必要がありますが、JavaもC ++もどちらも優先しないため、それが重要なポイントだと思います。

setVisible()はこれらの理由で好まれるべきだと思う:

  1. 逆関数が何であるかはすぐにわかります。反対のsetVisible(false)場合はsetVisible(true)、逆にhide()簡単に呼び出しreveal()ます
  2. コードでどの状態をとるべきかを判断するときは常に、プログラム的に簡単です。つまりsetVisible(wantToSee)ifステートメントを使用するのではなく、呼び出すことができます。
  3. 似たような関数が複数あると、setX()形式が一般化されるため、一貫した関数のセットが得られますが、動詞のアプローチでは、探しているものがわからない場合は見つけるのが困難な多くの関数が生成されます。APIの一貫性により、APIの学習と記憶が大幅に容易になります。

3
C ++にはプロパティはありませんが、無料の関数があるため、新しいメンバー関数を追加せずに、つまり結合度を低くして、クラスインターフェイスを拡張できます。
フレネル14年

Qtは多くの場合、3つすべてを便宜として提供しているため、hide /)とshow()はシグナル/スロットシステムを使用して他のイベントに直接接続できます。これは実際にはスロットシステムの制限です— boost :: functionsのようなものを使用している場合、コールバックの設定時にtrue / false引数をバインドできます。

1
「プロパティをサポートする言語では、これらを優先する必要がありますが、JavaもC ++も優先しないので、それが重要なポイントだと思います。」必ずしも。ゲッター/セッターを優先しますか?はい。しかし、set_visibleは実際にはセッターではありません。
マイルルーティング14年

19

コンテキストで表示と非表示が何を意味するかに依存します。最初に、どちらが「主な方法」であるかを把握し、それを開発することに焦点を合わせます。

  • 選ぶ理由 setVisible(bool)
    • 単純なビットフリップであるか、オブジェクトが主に状態を保持しています
    • オブジェクトはほとんどの時間をCRUDフレームワークで費やします
    • 表示と非表示の間に簡単に共有できるコードがたくさんあります
  • 選ぶ理由show()hide()
    • そのようなオブジェクトがために、そのコンテナのすべてをチェックしなければならないときなどに実行されている重要な副作用やロジックがたくさんありますが、その表示状態、または遷移アニメーションをトリガーが。
    • 意図を表現することが重要なドメインモデルの一部ですか

さて、「ゴールドスタンダード」のコアをコーディングしたので、オブジェクトを使用する人が楽になるように、他のスタイルに薄い便利なメソッドを追加する価値があるかどうかを把握する必要があります。

  • の便利さ setVisible(bool)
    • 些細な条件を持ち、可視性のみに影響するifステートメントを回避できます(例setVisible(a==b)
    • 特定のゲッター/セッターフレームワークに配線できます(発生することが予想される場合)
  • 利便性show()hide()
    • ファーストクラスの関数とコールバックを備えた言語で役立ちます(例onSuccess(widget.show)
    • スタックトレースとパフォーマンスプロファイリングを使用すると、プログラムが何をしようとしていたかをすぐに確認できるため、読みやすくなります。

TLDR:最も重要なものを見つけて実装し、他のスタイルを薄い便利なメソッドとして追加する価値があるかどうかを自問してください。


11

「3つすべて」と言います。

Show()そして、Hide()よりも簡単にokでる傾向がSetVisible(true)ありSetVisible(false)ます。ただし、論理的に可視性を設定する場合はboolifaround thatを構築するよりもaを取得するメソッドを使用することをお勧めしますbool

ロジックと最小限の定型文を複製せずに3つすべてをサポートできます。

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

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

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

あるいは、ラップしているものにもっとSetVisibleっぽいAPIがある場合:

void Show() {
    SetVisible(true);
}

void Hide() {
    SetVisible(false);
}

void SetVisible(bool visible) {
    foo.SetVisible(visible);
    bar.SetVisible(visible);
}

40
マイクロソフトは、このアプローチを使用して開始および停止しSystem.Windows.Forms.Timerます。個人的には、これは紛らわしいと思います。両方とも私が見たときShowSetVisible、私の最初の傾きは、2つの機能の間にいくつかの重要な違いがあるかどうか疑問です。
ブライアン14年

1
ただし、それらを簡単に文書化して、その混乱を排除できます。これは単純な例なので、私はしませんでした。
ギャリーシャトラー14年

20
クラスを快適に使用できるようになる前に、ドキュメントを読むのにX分余分に費やす必要がありますか あるいは、混乱する(またはバグを導入する)余分な時間Xを無駄にする必要がありますか?確かに、Xはこの種のものにはかなり小さいですが、それは間違いなくゼロではありません。3つのオプションをすべて提供するということは、必要な機能の3倍の機能を提供することを意味します。さらに、クラスを使用するときに、異なる開発者が一貫性を保つもう1つの方法を紹介します。
ブライアン14年

5
これは、SOLID原則の1つであるInterface Segregation原則の明らかな違反です。あなたのアプローチに対する別の意見は、netbeansのデザイナーであるjaroslav tulachからのもので、彼の本の実用的なAPIデザインでAPI内で1つのことを行う唯一の方法を提供することを何度も主張しています。
アルフレードカサド14年

@AlfredoCasado同意します。SetVisibleが保護されていた場合はどうなりますか?サブクラスからアクセスできますが、このインターフェイス(APIなど)で特定のエンティティを呼び出すには、非表示/表示にする必要があります。
ピエールアラード14年

5

私はshow()とhide()を好みます。実際、1つのブール値を受け取るすべてのメソッドは、APIの意図をよりよく表現する2つのメソッドに変更できます。たとえば、クリーンなコードのRobert Martinは、引数が1つのメソッドよりも引数のないメソッドを推奨しています。

私にとってのもう一つの重要な議論は読みやすさです。私の意見では、良いコードは散文のように読むことができます。ソフトウェアプログラムでの言語構築は、完全に可能な場合により自然な言語を使用しますか?


1
アセンブラーの散文では不十分ですか?
アレクサンダー14年

シーケンスit.setVisible(false); it.setVisible(true);がコントロールの親の可視性に影響を与えたり、コントロールのZの順序や場所に影響を与えたりしないことを期待します。対照的に、hide(); show(); コントロールの親を非常にもっともらしい形で強制的に表示し、他のコントロールの上に移動し、その位置を見える場所に限定することができます。場合によっては、実際に何かが実際に見えるようにする手段があると便利です(前述のようにshow()、他の場合は、何も変更せずに可視性フラグを変更すると便利です。
supercat 14年

オブジェクト指向APIには「フラグ」はなく、OOはメッセージングに関するものであり、オブジェクトの状態である「フラグ」を変更することではなく、他のオブジェクトに何らかのタスクを実行することを伝えます。コントロール、親、z順序、およびおそらく他のAPIでの以前の経験に基づいて期待することについて、多くの仮定を立てています。これは、ドメインに関する個人的な感情や仮定に基づいてAPIを設計するという非常に悪い考えです。
アルフレードカサド14年

5

メソッドが表現力豊かであればあるほど、コードは読みやすくなり、その結果、保守が可能になると思います。次の2つのケースを考慮してください。

事例1:

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

ケース2:

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

最初のケースでは、関数「setVisible」が何をしているのかは明確ですが、読みたい場合は次のように言います。

顧客が有効になっている場合は顧客パネルを表示し、無効になっている場合は非表示に設定します。

より説明的な言い方をすると:

  • 顧客のステータスを確認します。
    • 顧客が有効になっている場合、顧客のパネルを表示します
    • それ以外の場合は、非表示にします

これにより、「ケース1」機能が次のように変更されます。

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

より多くのコードを生成しますが、より読みやすくなります。

2番目のケースには明らかな欠陥があります。つまり、パネルを表示することは既にわかっているので、「表示」機能を使用しないのはなぜですか。

「setVisible」の使用が絶対に間違っていると言っているわけではありませんが、時間の経過とともに書かれていないコードを読み込もうとすると混乱を招きます。


私は言うだろう:show customer panel iff the user/customer is enabled。あなたの例ほど読みにくい複雑な条件がたくさんあるかもしれないことに同意しますが、それらの場合、それらの条件を異なる行に分割します。
ComFreek

5

Hide()/ Show()の方が魅力的だと思います。何が起こっているのかを理解するのが簡単だからですSetVisible(true)。一方、多くの条件を回避できるので、単一の関数が望ましいです。

その場合は、私はへの入力として列挙体を使用することをお勧めSetVisibleので、あなたはどちらかを取得SetVisible(Visibility.Visible)またはSetVisible(Visibility.Hidden)。実行されているアクションを即座に読み取ることができる単一の機能があります。

Javaの命名規則を使用すると、多分setVisible(Visibility.VISIBLE)またはになりsetVisible(Visibility.HIDDEN)ます。


3

Darienの答えに同意しますが、C#プログラマーの観点から視点を追加したかったです。

「setXXX」と書かれたコードを見たとき、それが物に値を設定していると言って読んだとき、その値に設定すること以外にそのことで副作用があるとは思わず、これはべき等であると期待しています(つまり、同じ値を設定し続けることができ、大丈夫です)。むしろフィールドにアクセスするようなものです。一般に、「setXXX」とともに「getXXX」メソッドも表示されることを期待しています。

これがJavaとC ++で期待されるものかどうかはわかりませんが、C#では期待されますが、C#ではプロパティと呼ばれる短い手があります。そして、プロパティの使用方法に関する優れたガイダンスがあります(http://msdn.microsoft.com/en-us/library/ms182181.aspx)。

このビューを考えると、次に選択するインターフェイスは、副作用があるかどうかにのみ依存します(そのフィールド値を変更する以外):

アクションの実行に副作用がある場合、たとえばダイアログボックスが表示される場合は、「Show()」および「Hide()」を使用します。

副作用がない場合は、「ウィジェット」の可視性を設定していて、その状態に応じて他のウィジェットがそのウィジェットをレンダリングする場合、setVisibilityまたはsetIsVisibleを使用します。(SetVisibleとは呼びません)。

C#(Javaについてはわかりません)では、オブザーバーパターンを採用するのが一般的です。UIフレームワークはオブジェクトの変更をリッスンし、Visibilityなどのプロパティが変更されるとUIを自動的に再レン​​ダリングします。つまり、setIsVisibleを呼び出して値を設定すると、副作用があるように見えますが、私の定義ではそうではありません。ウィジェットのコントラクトは、「IsVisible」を表すフィールド値を設定することで満たされます。

別の言い方をすれば、フォームが表示される前にフォームのラベルの表示を切り替えることは問題ありません。つまりlabel.getIsVisible == trueですが、フォームは表示されません。

フォームが表示されていないときにHide()を呼び出すことはできません。


1
副作用なしでフィールドにアクセスする方法としてのあなたの説明getXXX()setXXX()メソッドは、C#ではなく Javaのように聞こえます。これは、プロパティがないためJavaで行う必要がある方法です。C#でそのようなコードを見たら、C#のプロパティについてまだ学んでいないJava開発者によって書かれたと思います。
gilly3

+1 SetVisibility
akaltar 14年

@ gilly3-はい、もちろん。また、「プロパティ」はCLRに存在せず、C#はILのget_XXXおよびset_YYYメソッド呼び出しに変換されます。私のポイントは、質問の文脈で、JavaでsetXXX、getXXXを見た場合、C#のプロパティと同じセマンティクスで動作するはずです。それは事実です。C#のプロパティに関する同じガイドラインが、JavaのsetXXXとgetXXXのペアに適用できると思います。私は投稿で参照するガイドラインにたまたま同意します。したがって、インターフェイスを定義するときにJavaでこのシナリオで使用するための同じガイドラインを提唱しています。
ダニエルジェームズブライアーズ14年

1
「副作用」を意味する場合、「「観測可能な」ものに関連するもの以外」を意味することを明確にすることが役立つ場合があります。私が好むルールは、getXX呼び出しに対応するsetXXメソッドがある場合、setYYそれに影響を与えるべきgetZZではないが、setZZメソッドを持たない呼び出しに影響を与える可能性があるということです。
supercat

2

インターフェースを少し変更することをお勧めします。

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

より良い名前

これらのメソッド名は、開発者が実行する必要があるものに基づいて使用するメソッドを決定するのに役立ちます。一方SetVisible(bool visible)、それは同じ意味論的な意味を伝えるために、開発者を混乱させることShow()Hide()Toggle()行動を決める条件が存在することを意味します。したがって、各メソッドをいつ使用するかは開発者にとって直感的になります。

コードの冗長性の削減

インターフェイスに複数のメソッドがあることの利点は、呼び出しコードが簡素化されることです。あなただけ公開することができShow()、およびHide()、しかし:

  • おそらくSetVisible()、舞台裏で実際の作業を行う(またはShow()andの冗長コードを記述するHide())には、何らかのプライベートメソッドが必要です。
  • 呼び出しコードには、使用するメソッドを選択するためだけに、多くの冗長if / elseブロックが含まれている場合があります。これは私の意見ではコードを肥大化させます。
  • 私が消費者であれば、コードの肥大化を避けるためにSetVisible()(またはToggle()冗長なコードを)実行する独自のラッパー関数を作成するだけです(冗長なコードは嫌いです)。したがって、おそらく実装でプライベートメソッドとして既に存在するメソッドを複製します。

1
メソッドの複製は理にかなっているように思えますが、私はそれをしません。一方、toggleVisible(bool)が直感的であることには同意しません。私には、渡されたboolがtrueであればトグルする必要があることを意味します。偽装の集合関数であるとは想定していません。
パトリックM 14年

0

SetVisible(bool)可視性を2回切り替える(表示と再表示、または非表示と再表示)だけで、操作が実行される前と基本的に同じ状態のままになる場合にのみ使用することをお勧めします(表示と再表示の場合は問題ありません) 「自動的に」発生することが予想される場合、何かまたはその逆は、オブジェクトを再描画する必要があります)。オブジェクトの非表示と表示が1ビットの状態を変更する以外の効果を持たない場合、外部のコードが可視性パラメーターを受け入れるメソッドを持つことは理にかなっており、そのようなコードの記述はによって促進されSetVisibleます。

オブジェクトを非表示にして再表示すると、Zの順序を変更するなどの副作用が発生する可能性がある場合、そのようなアクションは別の方法で実行される可能性が高くなります。そのような場合、「可視性」パラメーターを受け入れる外部メソッドの有用性は制限され、そのため、それらを容易にする利点はほとんどありません。さらに、SetVisibleメソッドは(間違って)副作用なしにオブジェクトの可視性の変更を実現できることを示唆します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.