親メソッドと子メソッドが衝突したとき!
TL;DR: 子クラスが使用できる名前を持つプライベート メソッドを親クラスで使用しないでください。
親クラスと子クラスで同じメソッド名を使用すると、混乱が生じます。
子クラスに同じ名前のパブリック メソッドが存在する場合でも、親クラスのプライベート メソッドをオーバーライドすることはできません。
これは、ほとんどの静的言語の設計に見られる問題です。この断絶によりバグが発生し、コードの保守が困難になります。
<? class ParentClass { private function greet() { // This method is private return "Hello from ParentClass"; } public function callGreet() { return $this->greet(); } } class ChildClass extends ParentClass { public function greet() { // Overriding a concrete method is a code smell // Compilers SHOULD warn you return "Hello from ChildClass"; } } $child = new ChildClass(); echo $child->callGreet(); // When callGreet() is invoked on the $child object, // it executes the following: // It calls $this->greet(), // which refers to the greet() method of ParentClass // because the original method is private // and cannot be overridden or accessed from ChildClass. // The unexpected output is 'Hello from ParentClass'
<? class ParentClass { protected function greet() { // notice the 'protected qualifier' return "Hello from ParentClass"; } public function callGreet() { return $this->greet(); } } class ChildClass extends ParentClass { public function greet() { return "Hello from ChildClass"; } } $child = new ChildClass(); echo $child->callGreet(); // The output is "Hello from ChildClass" // This is the standard (and wrong) solution // Also fixed by most AIs
<? abstract class ParentClass { // Declare greet() as an abstract method // Following the template-method design pattern abstract protected function greet(); public function callGreet() { return $this->greet(); } } class ChildClass extends ParentClass { protected function greet() { return "Hello from ChildClass"; } } class OtherChild extends ParentClass { protected function greet() { return "Hello from OtherChild"; } } $child = new ChildClass(); echo $child->callGreet(); // Output: Hello from ChildClass $otherChild = new OtherChild(); echo $otherChild->callGreet(); // Output: Hello from OtherChild
この臭いは、親クラス内のプライベート メソッドを探し、子クラスが同じ名前のメソッドを定義しているかどうかを確認することで検出できます。また、プライベート メソッドを呼び出す親メソッドもテストする必要があります。
明確で予測可能なコードは、モデル化する現実世界の階層を反映する必要があります。
名前が重複するプライベート メソッドを使用すると、モデルと実装の間にバイジェクションギャップが生じます。
このギャップにより、開発者は混乱し、欠陥が増加し、クリーン コードの原則に違反することになります。
AI ジェネレーターは、定型的な親子関係を生成するときに、この臭いを頻繁に発生させます。
アクセス レベルをチェックしなかったり、継承の影響を考慮しなかったりする可能性があります。
AI ツールは明確な指示でこの臭いを修正できます。
AI に重複するメソッド名をチェックしたり、階層をリファクタリングしたりするように依頼できます。
ぜひお試しください!
覚えておいてください:AIアシスタントは多くの間違いを犯します
適切な指示がなければ | 具体的な指示 |
---|---|
親クラスと子クラスを設計するときは、継承とアクセシビリティを明確に定義するメソッドを使用する必要があります。
子メソッドと重複するプライベート メソッドは避けてください。これにより、コードの可読性と拡張性が維持され、クリーン コードの原則に準拠した状態が保たれます。
Pythonなどの言語では、名前に関係なく親メソッドをオーバーライドできますが、 Java ではアクセス レベルが厳密に適用されます。
C#はJavaと同様に動作します。これらの違いは、予期しない動作を回避するために、使用している言語の特定のルールを理解する必要があることを意味します。
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxviii
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xii
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-iii-t7h3zkv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-viii-8mn3352
免責事項: コードスメルは私の意見です。
継承は良いことですが、密結合が導入されることを決して忘れてはなりません。
ロバート・C・マーティン
この記事は、HackerNoon の CodeSmell シリーズの一部です。