paint-brush
コードの臭い 286 - 親子メソッドの重複@mcsee
新しい歴史

コードの臭い 286 - 親子メソッドの重複

Maximiliano Contieri4m2025/01/16
Read on Terminal Reader

長すぎる; 読むには

親子クラスでプライベート メソッドが衝突すると、バグやコードの臭いが発生する可能性があります。明確な命名を維持し、重複を避け、クリーンなコード プラクティスに従うことで、この問題を回避します。親クラスのメソッドには、子クラスが使用できる名前を付けます。
featured image - コードの臭い 286 - 親子メソッドの重複
Maximiliano Contieri HackerNoon profile picture
0-item

親メソッドと子メソッドが衝突したとき!


TL;DR: 子クラスが使用できる名前を持つプライベート メソッドを親クラスで使用しないでください。

問題点

  • 最も驚きが少ない原則違反
  • 予期しない動作や欠陥
  • 隠れた依存関係
  • 拡張性が限られている
  • コードの曖昧さ
  • オープン/クローズ原則違反
  • 誤解を招くデザイン

ソリューション

  1. 階層構造を避ける
  2. プライベートメソッドの名前を変更する
  3. 明確な命名を維持する
  4. 名前の重複を避ける
  5. 保護されたメソッドを避ける
  6. コードを再利用するのではなく、重要な関係に基づいてサブ分類する

コンテクスト

親クラスと子クラスで同じメソッド名を使用すると、混乱が生じます。

子クラスに同じ名前のパブリック メソッドが存在する場合でも、親クラスのプライベート メソッドをオーバーライドすることはできません。

これは、ほとんどの静的言語の設計に見られる問題です。この断絶によりバグが発生し、コードの保守が困難になります。

サンプルコード

間違っている

<? 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

検出

  • [x]セミオートマチック

この臭いは、親クラス内のプライベート メソッドを探し、子クラスが同じ名前のメソッドを定義しているかどうかを確認することで検出できます。また、プライベート メソッドを呼び出す親メソッドもテストする必要があります。

タグ

  • 階層

レベル

  • [x]中級

なぜ一対一変換が重要なのか

明確で予測可能なコードは、モデル化する現実世界の階層を反映する必要があります。

名前が重複するプライベート メソッドを使用すると、モデルと実装の間にバイジェクションギャップが生じます。

このギャップにより、開発者は混乱し、欠陥が増加し、クリーン コードの原則に違反することになります。

AI生成

AI ジェネレーターは、定型的な親子関係を生成するときに、この臭いを頻繁に発生させます。

アクセス レベルをチェックしなかったり、継承の影響を考慮しなかったりする可能性があります。

AI検出

AI ツールは明確な指示でこの臭いを修正できます。

AI に重複するメソッド名をチェックしたり、階層をリファクタリングしたりするように依頼できます。


ぜひお試しください!

覚えておいてください:AIアシスタントは多くの間違いを犯します

適切な指示がなければ

具体的な指示

チャットGPT

チャットGPT

クロード

クロード

困惑

困惑

副操縦士

副操縦士

ジェミニ

ジェミニ

結論

親クラスと子クラスを設計するときは、継承とアクセシビリティを明確に定義するメソッドを使用する必要があります。

子メソッドと重複するプライベート メソッドは避けてください。これにより、コードの可読性と拡張性が維持され、クリーン コードの原則に準拠した状態が保たれます。

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


免責事項: コードスメルは私の意見です。

クレジット: Matt ArtzによるUnsplashの写真


継承は良いことですが、密結合が導入されることを決して忘れてはなりません。

ロバート・C・マーティン


この記事は、HackerNoon の CodeSmell シリーズの一部です。