純粋な機能を非公開にする正当な理由はありますか?


25

同僚と少し議論をしました。簡単に言えば、純粋な関数を非表示/カプセル化する正当な理由はありますか?

「純粋」とは、ウィキペディアの定義を意味します

  • 同じ入力から常に同じ結果を返します。(この説明のために、値のセマンティクスがないFoo Create(){ return new Foo(); }場合Fooは不純であると見なされます。)
  • 可変状態(ローカル変数を除く)またはI / Oは使用しません。
  • 副作用を引き起こしません。

26
そのような関数をクラスのメンバーにしないようにするための議論があるかもしれません。
ピーターB

6
@PieterB-確かに、すべての言語がそれをサポートしているわけではありません。また、一部の言語は、無料の機能であっても内部モジュールを許可します。
テラスティン14

3
あなたの意見は?関数の純度は、パブリックAPIに属しているかどうかとは関係ないと思います。
アンドレス

@andresF。-実際には、非バインド検証ルールを公開すべきかどうかについて議論が行われました。私は、それが純粋な関数であるため、害はほとんどないと主張しました。この特定のインスタンスでは、テスト容易性に役立ち、再利用される可能性がありました。この質問は、その議論がどれだけ広く適用できる/適用されるべきかについての詳細です。
テラスティン14

2
@Telastyn再利用可能であるが、現在のクラスの責任の一部ではない場合、おそらく別のクラス/モジュール/あなたの言語が持つものでなければなりません。次に、新しいクラス/モジュールの責任の一部であるため、必然的に公開されます。テストについて言及しているので、それを行うときに必ずしもメソッドをモックアウトする必要はないことに注意してください。「実装の詳細」として、テスト中にモックを作成してもほとんどメリットはありません。
jpmc26 14

回答:


76

純粋な関数はまだ実装の詳細である可能性があります。(重要な不変式/契約を壊さないという観点から)この関数は害を及ぼさないかもしれませんが、そのクラス/モジュール/パッケージの作者とユーザーの両方を失うことで公開します。作成者は、実装が変更され、関数がもはや役に立たなくても削除できないため、失います。ユーザーは、APIを理解するためにAPIの使用に関係のない余分な機能を選別して無視する必要があるため、失います。


33
+1。クラスのパブリックメンバーはそのAPIです。「公開されている場合、私を傷つけることはできますか?」という質問ではなく、「APIの一部である必要がありますか?」
オーダス14

1
私が追加したいのは、他の場所で同様の関数がポップアップし始めたら、それを別のクラスにリファクタリングして、複数のクラスがそれを利用できるようにすることです。または、それが最初に懸念される場合は、最初に別のクラスで定義します。
jpmc26 14

1
同様に拡張することを意図していない公開クラスを封印します。
デン

関数(またはクラス)の非表示または表示は主にAPIの保護と保守の問題であり、コードの種類とは関係がないことを指摘するための+1です。
マルコ14

42

問題は逆向きです。

機能を非公開にする理由を探さないでください。(私の意見では)そもそも間違った考え方です。推論は逆の方向に進む必要があります。

言い換えれば、「なぜプライベートにするのか」と聞かないでください。質問:「なぜ公開するのですか?」

疑わしい場合は、公開しないでください。それはオッカムの剃刀のようなものです-必要以上にエンティティを増やすな。

編集:コメントで@Telastynによって提起された反論に対処する(そこでの議論の拡大を避けるため):

私はそれを時間をかけて聞いて、かなり長い間それを支持しましたが、私の経験では、物事はあまりにもプライベートになる傾向があります。

はい、クラスが継承のために開かれている場合は苦痛ですが、一部のプライベートメソッド(動作を変更したい)をオーバーライドすることはできません。

しかし、protectedそれで十分です-それはまだ非公開です。

「公開されるべきではないもの」を取得するために、多くのコードの重複とオーバーヘッドが発生しますが、とにかく間接的にアクセスされます。

問題が発生した場合は、単に公開するだけです!私が話していた必要性があります:)

私のポイントは、万が一に備えてそれをすべきではないということです(YAGNIおよびすべて)。

プライベート機能をプライバシーに戻すよりも、プライベート機能を公開する方が常に簡単であることに注意してください。後者は既存のコードを壊す可能性があります。


私はそれを時間をかけて聞いて、かなり長い間それを支持しましたが、私の経験では、物事はあまりにもプライベートになる傾向があります。「公開されるべきではないもの」を取得するために、多くのコードの重複とオーバーヘッドが発生しますが、とにかく間接的にアクセスされます。
テラスティン14

3
@Telastyn IMHO、アプリケーションが設計ミスに苦しんでいるようですね。個別のコードパスを介してメソッドを呼び出す必要があるためにメソッドを公開する傾向がある場合、特に純粋な関数の場合は、このメソッドを適切な場所に挿入または含めることができる独自のモジュールに分割する必要があることを示している可能性があります。
レオ14

@leo-すみません、私は従いません。整数より小さいような関数を考えます。これは、適切な場所にインジェクトおよびインクルード(または単に使用)できるため、具体的に公開されている素晴らしい純粋な関数です。
テラスティン14

5
@Telastyn私の意見では、これは「すべてがオブジェクト/クラスである」という哲学の兆候であり、一部のOOP言語にはクラス以外の複合データ型がないという事実が組み合わされています。誰かが2つの値を同時に渡す必要があるとすぐにクラスを作成し、すべての同僚とスタイルチェックソフトウェアがそれらのフィールドをプライベートにするように指示します。
ドーバル14

@Telastynそう。つまり、 'integerLessThan'メソッドがパブリックメソッドのカプセル化された実装の詳細として開始されたが、他の場所でプライベートメソッドを呼び出す必要がある場合、それはおそらくプライベートメソッドが別の場所に属していることの兆候ですモジュール/パッケージ/クラス。これにより、それを呼び出すロジックとは無関係にインポートできます。メソッドをそのまま公開するということは、メソッドが有用だと思った最初のモジュールに任意に配置されることを意味します。
レオ14

6

関数を非表示/カプセル化する決定は、その純度に依存するとは思わない。関数が純粋だからといって、外部がそれについて知る必要があるわけではありません。興味深いことに、関数が純粋であり、パブリックであることが意図されている場合、インターフェイスのインスタンスメンバーである必要はないかもしれませんが、静的としてより適しているかもしれません。ただし、これもすべてコントラクトの意図に依存し、この場合は機能の純度ではなく、機能の論理的なグループ化に依存します。


5

クラスは単一責任原則に従うべきです。クラスは、その目標を達成するために他の機能を呼び出す必要があるかもしれませんが、単一の責任の一部である関数のみを公開する必要があります。

これは、可視性問題を引き起こす可能性ある場合のほんの一例です。

ウィジェットをフロブニケートするクラスを考えます。フロブニケーションコードの一部として、文字列を解析するユーティリティ関数が必要な場合があります。おそらく、標準の文字列関数がサポートしない方法でウィジェット名を変換する必要があります。

これは純粋な関数(文字列が入力され、何らかの方法で変換され、新しい文字列を返す)であるため、結果はパブリックまたはプライベートになります。それともできますか?

パブリックにすると、クラスには2つの責任があります。ウィジェットのフロブニケートと、ストリングの変換です。これはSRPに違反し、他のクラスが関数に依存するようになると問題を引き起こす可能性があります。これはクラスの内部でのみ使用されると思われるものなので、おそらくそのインターフェイスまたは可視性を変更します。現在、システムの他の部分のクラスは壊れています。

関数をプライベートに保つことにより、クラスの単一の責任の一部ではないコードに依存する機会は誰にもありません。


2
ただ公開するのではなく、単一の責任の一部である関数のみを含めるべきだと主張します。
テラスティン14

1
灰色の領域があると思います。StringTransformer1か所でのみ使用される2行または3行のコードをカプセル化するために、別個のクラスが本当に必要ですか?コードが複数の場所で使用されたら、1つの責任で新しいクラスに分けるのが最善ですが、トレードオフがあります。

確かに。ガイドラインはルールであり、ガイドラインではありません。
テラスティン14

非Javaの@snowmanでは、関数のライブラリを作成するだけです。
ピーターB 14

@PieterBそれはJava v。についてではありません。本当にオブジェクト指向にするためには、ファクトリー、いくつかの抽象クラスなどが必要になります。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.