8

以下のように親クラスの下にサブクラスを定義するのは慣例ですか?

class Element

  class Div < Element

  end

  class Paragraph < Element

  end

end

それとも、サブクラスを含むモジュールを作成する方が適切ですか?

class Element

end

module Elements

  class Div < Element

  end

  class Paragraph < Element

  end

end

または、モジュール内に「基本」クラスを作成し、同じモジュール内でサブクラスを定義するには?

module Element

  class Base

  end

  class Div < Base

  end

  class Paragraph < Base

  end

end

それとも、命名規則を強制する方が良いですか?

class Element

end

class DivElement < Element

end

class ParagraphElement < Element

end

すべてのライブラリが異なる名前空間/命名規則を選択しているようです。

使用するのに最適なのはどれですか?
それぞれの長所と短所は何ですか?

4

3 に答える 3

9

TL; DR:これを行うための最も一般的で最良の方法は、基本クラスとそのサブクラスを含むモジュールを使用することです。しかし、すべてを調べてみましょう。

これに関する公式の情報源は多くありません。ただし、モジュールを使用してライブラリ、コード、およびクラスのグループを含めるのがスタイルです。

スーパークラスのサブクラス

長所

  • 自己完結型:クラスシステム全体が1つの名前で含まれています

短所:

  • 不自然:スーパークラスの内部でサブクラスを探すのは誰だと思いますか?

スーパークラスにサブクラスを含めることは、実際には状況によって異なります。ただし、このメソッドの利点は、モジュールメソッドによっても実現されます。しかし実際には、これは行われていません。クラスには、メソッド、インスタンス変数、クラスメソッドなどが含まれます。ただし、クラスはネストの最後のレベルと考えることができます。非常に特殊な状況でない限り、クラスにクラスはありません。

これが理にかなっていると私が考えることができる1つのケースは、サブクラスが使用される唯一の方法がスーパークラスを介する場合です。たとえば、、などのFormatter内部サブクラスを持つクラスです。これらのクラスは、何かをすることによってのみ使用するとします。のように。しかし、これを行う場合、サブクラスはプライベートであり、とにかく外の世界にアクセスできないようにする必要があります。そしてその時点で、継承は非常にC ++ yの方法であり、Rubyishではありません。XMLPDFFormatter.new(:xml)

モジュール外の基本クラス、内のサブクラス

長所:

  • 何も思いつかない

短所:

  • 非接続を意味します:Elementがその子と同じ名前空間にない場合、名前を超えて、それが関連していることを私に教えてくれますか?

この方法は非常に不自然です。子とは何の関係もないように見えますElement。別の見方をすれば、子は処理されない内部実装の詳細であるように見えます。いずれにせよ、それはぼろぼろでずさんなネーミングと悪いコード構造計画のように見えます。これを使用してコードを読んでいた場合、Elementsモジュールの内容を調べて、それElementがサブクラス化されていることを確認する必要があります。これは、最も自然なことではありません。

モジュール内のクラスとサブクラス(最良のソリューション)

長所:

  • 含まれるもの:スーパークラスとすべてのElementクラスは、1つの名前空間に含まれているため、簡単にインポート、要求、反復などできます。メタプログラミングも支援します。
  • include含めることができます:クラスは任意のコードに簡単に組み込むことができます。
  • 明確:Elementとサブクラスの間には明らかな関連性があります。それらは明らかに機能のバンドルです。

短所:

  • 怠惰な命名を奨励する:これは、クラスBaseに非常にあいまいな名前を付けることを奨励します。

これが最善のアプローチです。それはクラスをきちんとしたバンドルにしますが、それでも明白な関連性と明白な「ここで、私のDivクラスを使用してください」を示します(クラス内のサブクラス戦略とは対照的です)。また、これはメタプログラミングに非常に役立ちます。メタプログラミングでは、すべてをモジュールに含めることが、物事を機能させるために重要です。最後に、これは、、、などautoloadの構造でうまく機能します。これらは、これが言語が使用されるように設計された方法であることを示しています。require_relativeinclude

命名規則を強制する

長所:

  • シンプル:ここでは複雑さはありません。
  • Divあいまいさを取り除く:またはのような短い名前をandParaに変換することにより、あいまいさを取り除きます。DivElementParaElement

短所:

  • 古語法:クラスまたはメソッドをグループ化するための命名規則は、CやObjective-Cなどのより良い方法がない言語でのみ存在する必要があります。C ++は、名前空間を取得するとすぐにそれを削除しました。
  • プログラムによるグループ化なし:これらの命名規則は、人間には明らかですが、クラス構造をメタプログラミングコードに対して非常に曇らせ、プログラムがクラスをグループとして処理することを不可能にします。
  • グローバル名前空間を汚染する:これにより、グローバル名前空間に多数の名前が作成されますが、これは常に悪い考えです。

これは非常に非常に悪い解決策です。それは、ほとんど組織化されておらず、ほとんど意味のない、ずさんなCスタイルのコードを書くことを奨励しています。これらの種類の命名規則は、より良い解決策がない言語でのみ使用する必要があり、Rubyにはより良い解決策がたくさんあります。配列内のすべてのクラスを定義することでさえ、命名規則よりも優れています。

注:ただし、本当に必要な場合は、モジュール内に保持している限り、Divまたはのような短い名前に命名規則を定義できます。ただし、これはDRYに違反するため、お勧めしません。ParaElements::DivElement

結論

したがって、実際には2つのオプションがあります。すべてをモジュールに入れるだけです。

module Elements
  class Element; end
  class Div < Element; end
  #etc...
end

または、すべてを命名規則のあるモジュールに入れます。

module Elements
  class Element; end
  class DivElement < Element; end
  #etc...
end

明確さ、標準的な方法の使用、およびメタプログラミングの理由から、前者を推測します。

于 2013-02-23T16:12:59.030 に答える
3

これは私が何度も直面した問題です。いくつかの共有機能とそれを使用するいくつかの異なる実装クラスがあります。共有機能と実装クラスの名前空間が同じ名前を持つのは自然なことです。

最初の例のように、親クラスの下にサブクラスを定義する際に問題が発生したことはありませんが、私のチームの他の開発者を混乱させることがあるという事実を除いて. ですから、誰と一緒に仕事をしているか、また彼らの好みにもよりますが、このアプローチに問題はないと思います。

意味のある名前があれば、名前空間に別の名前を付けた2番目のアプローチを引き続き好むでしょう。そうでない場合は、最初のアプローチを使用します。

Baseの意見では、この種の一般的な名前はそこに古いものを投げ込むことを奨励するため、クラスが何をするかを説明する名前は(うまくいけば)メソッドを追加するたびに考えさせますそれは本当にそこに属しています。

そして、私はあなたの命名規則の例のように複合名のファンではありません。これは、データベースの正規化のようなものであるという漠然とした感覚で自分自身に正当化します-各フィールド(またはクラス名)には1つの情報のみを含める必要があります。

とにかく、これがお役に立てば幸いです。この質問に対する絶対的な答えはないと思うので、私自身の経験以外の情報源から引き出すことはできません (それが「信頼できる」と思うかどうかは、あなたが判断してください)。それは大部分が主観的です。

于 2013-02-23T15:00:08.723 に答える
1

名前空間と継承は目的が異なります。名前空間を使用して、モジュールを別のモジュール内にカプセル化します。継承を使用して、デフォルトとして別のメソッド/変数/定数を使用してモジュールを定義します。

原則として、モジュールを名前空間内に置き、同じ単一モジュールから継承する必要がある場合がありますが、それはユースケースによって異なります。特定のユースケースについて議論しなければ、提示された方法の中でどの方法が最適かを判断することはできません。

于 2013-02-19T21:55:45.973 に答える