同僚と少し議論をしました。簡単に言えば、純粋な関数を非表示/カプセル化する正当な理由はありますか?
「純粋」とは、ウィキペディアの定義を意味します。
- 同じ入力から常に同じ結果を返します。(この説明のために、値のセマンティクスがない
Foo Create(){ return new Foo(); }
場合Foo
は不純であると見なされます。) - 可変状態(ローカル変数を除く)またはI / Oは使用しません。
- 副作用を引き起こしません。
同僚と少し議論をしました。簡単に言えば、純粋な関数を非表示/カプセル化する正当な理由はありますか?
「純粋」とは、ウィキペディアの定義を意味します。
Foo Create(){ return new Foo(); }
場合Foo
は不純であると見なされます。)回答:
純粋な関数はまだ実装の詳細である可能性があります。(重要な不変式/契約を壊さないという観点から)この関数は害を及ぼさないかもしれませんが、そのクラス/モジュール/パッケージの作者とユーザーの両方を失うことで公開します。作成者は、実装が変更され、関数がもはや役に立たなくても削除できないため、失います。ユーザーは、APIを理解するためにAPIの使用に関係のない余分な機能を選別して無視する必要があるため、失います。
問題は逆向きです。
機能を非公開にする理由を探さないでください。(私の意見では)そもそも間違った考え方です。推論は逆の方向に進む必要があります。
言い換えれば、「なぜプライベートにするのか」と聞かないでください。質問:「なぜ公開するのですか?」
疑わしい場合は、公開しないでください。それはオッカムの剃刀のようなものです-必要以上にエンティティを増やすな。
編集:コメントで@Telastynによって提起された反論に対処する(そこでの議論の拡大を避けるため):
私はそれを時間をかけて聞いて、かなり長い間それを支持しましたが、私の経験では、物事はあまりにもプライベートになる傾向があります。
はい、クラスが継承のために開かれている場合は苦痛ですが、一部のプライベートメソッド(動作を変更したい)をオーバーライドすることはできません。
しかし、protected
それで十分です-それはまだ非公開です。
「公開されるべきではないもの」を取得するために、多くのコードの重複とオーバーヘッドが発生しますが、とにかく間接的にアクセスされます。
問題が発生した場合は、単に公開するだけです!私が話していた必要性があります:)
私のポイントは、万が一に備えてそれをすべきではないということです(YAGNIおよびすべて)。
プライベート機能をプライバシーに戻すよりも、プライベート機能を公開する方が常に簡単であることに注意してください。後者は既存のコードを壊す可能性があります。
クラスは単一責任原則に従うべきです。クラスは、その目標を達成するために他の機能を呼び出す必要があるかもしれませんが、単一の責任の一部である関数のみを公開する必要があります。
これは、可視性が問題を引き起こす可能性がある場合のほんの一例です。
ウィジェットをフロブニケートするクラスを考えます。フロブニケーションコードの一部として、文字列を解析するユーティリティ関数が必要な場合があります。おそらく、標準の文字列関数がサポートしない方法でウィジェット名を変換する必要があります。
これは純粋な関数(文字列が入力され、何らかの方法で変換され、新しい文字列を返す)であるため、結果はパブリックまたはプライベートになります。それともできますか?
パブリックにすると、クラスには2つの責任があります。ウィジェットのフロブニケートと、ストリングの変換です。これはSRPに違反し、他のクラスが関数に依存するようになると問題を引き起こす可能性があります。これはクラスの内部でのみ使用されると思われるものなので、おそらくそのインターフェイスまたは可視性を変更します。現在、システムの他の部分のクラスは壊れています。
関数をプライベートに保つことにより、クラスの単一の責任の一部ではないコードに依存する機会は誰にもありません。
StringTransformer
1か所でのみ使用される2行または3行のコードをカプセル化するために、別個のクラスが本当に必要ですか?コードが複数の場所で使用されたら、1つの責任で新しいクラスに分けるのが最善ですが、トレードオフがあります。