web-dev-qa-db-ja.com

C ++で名前空間を使用するためのベストプラクティス

ボブおじさんの クリーンコード を数か月前に読みましたが、コードの記述方法に大きな影響を与えました。彼がすべてのプログラマーが知っておくべきことを繰り返しているように見えたとしても、それらをすべてまとめて実践することで、はるかにクリーンなコードになります。特に、大きな関数を多数の小さな関数に分解し、大きなクラスを多数の小さなクラスに分解すると、非常に便利であることがわかりました。

さて、質問です。この本の例はすべてJavaで書かれていますが、私は過去数年間C++で働いています。 Clean Codeのアイデアは、Javaには存在しない名前空間の使用にどのように拡張されますか? (はい、Javaパッケージについては知っていますが、実際には同じではありません。)

それぞれが明確に定義された責任を持つ多数の小さなエンティティを作成するという考えを名前空間に適用することには意味がありますか?関連するクラスの小さなグループは常に名前空間にラップされるべきですか?これは、多数の小さなクラスを持つことの複雑さを管理する方法ですか、それとも多くの名前空間を管理するコストは法外なものでしょうか?

編集:私の質問はこれで答えられます ウィキペディアのパッケージ原則に関するエントリ

39
Dima

(私はクリーンなコードを読んでおらず、Javaについてあまり知りません。)

それぞれが明確に定義された責任を持つ多数の小さなエンティティを作成するという考えを名前空間に適用することには意味がありますか?

はい、複数のクラスと複数の関数へのリファクタリングと同じです。

関連するクラスの小さなグループは常に名前空間にラップされるべきですか?

実際には答えずに:はい、少なくとも1つのトップレベル名前空間を使用する必要があります。これは、プロジェクト、組織、または好きなものに基づくことができますが、グローバル名をほとんど使用しないことで、名前の競合を減らすことができます。その下にある他のものすべてをグループ化する単一の名前空間は、1つのグローバル名のみを導入します。 (extern "C"関数を除くが、これはCの相互運用性によるもので、他のextern "C"関数にのみ影響します。)

関連するクラスの小さなグループをそれらに専用の名前空間でラップする必要がありますか?おそらく。特に、これらのクラスに共通のプレフィックス(FrobberThing、FrobberThang、FrobberDoohickey)を使用している場合は、名前空間(frobber :: Thingなど)を検討する必要があります。これらがより大きなプロジェクトの一部である場合は、ルートネームスペースまたは別のネームスペースの下にあります。

これは、多数の小さなクラスを持つことの複雑さを管理する方法ですか、それとも多くの名前空間を管理するコストは法外なものでしょうか?

上記の接頭辞付きの名前の例では、frobber :: ThingをFrobberThingよりも管理するのは難しくありません。ドキュメントやコード補完などのツールを使用すると、さらに簡単になる場合があります。 ADLとの違いはありますが、これは有利に機能します。関連付けられている名前空間の名前が少ないほど、ADLを理解しやすくなり、宣言を使用して特定の名前を名前空間に注入できます。

ネームスペースエイリアスを使用すると、特定のコンテキストで長いネームスペースに短い名前を使用できます。これにより、再び使いやすくなります。

void f() {
  namespace CWVLN = Company_with_very_long_name;  // Example from the standard.
  // In this scope, use CWVLN::name instead of Company_with_very_long_name::name.
  namespace fs = boost::filesystem;  // Commonly used.
}

単一のルート名前空間、boost、そして多数のサブ名前空間を持つBoostを検討してください– boost :: asio、boost :: io、boost :: filesystem、boost :: tuplesなど–さまざまなライブラリー。 一部の名前は「昇格」されます ルート名前空間に:

すべての定義は名前空間:: boost :: tuplesにありますが、最も一般的な名前は宣言を使用して名前空間:: boostに引き上げられます。これらの名前は、Tuple、make_Tuple、tie and getです。さらに、refとcrefは:: boost名前空間の直下で定義されます。

「実際の」モジュールを使用する言語との最大の違いは、よりフラットな構造を使用するのが一般的であるということです。ネストされた名前を定義するために特別な努力をしなければ、それが機能するために、フラットな構造が使用されます。

23
Fred Nurk

すべてのコードに対して1つのマスター名前空間が必要です。これにより、名前空間に関して外部コードと区別されます。

マスター名前空間内では、サイズと複雑さに応じて、サブ名前空間を開くことができます。これは、名前がコンテキスト内の何かを明確に意味する場所であり、同じ名前が別のコンテキスト内で使用される場合があります。

特に、コンテキスト内で特定のことを意味するFileInfoのような一般的なサウンド名がある場合は、名前空間に配置します。

クラスを拡張することはできないため、このためにクラスを使用することもできます。そのため、ヘッダーを変更せずにクラスに新しい宣言を追加することはできません。

9
CashCow

名前空間はモジュールの概念ではないため、名前の競合が発生する可能性がある場合にのみ使用します。

3
Brainlag

深い名前空間が好きです(通常は3つのレベルを意味します)。

  • 会社名があります。
  • app/util/lib/etc
  • プロジェクト名/または適切なパッケージ

状況に応じて、私はもう1つのレベルを持っているかもしれません

  • 詳細(プラットフォーム固有の実装の詳細)
  • utils(まだ一般的なユーティリティに移動されていないユーティリティオブジェクト)。
  • 私が必要なものは何でも。
1
Martin York

Javaには名前空間がありますが、実際にはそう呼ばれていません。 javax.swing.*javaxはネームスペースで、swingはサブネームスペースです。 Javaパッケージについて何が書かれているのかを知るために本を読んだことはありませんが、同じ原則がどの言語の名前空間にもほとんど直接適用されます。

優れたヒューリスティックは、クラスに同じ接頭辞を何度も入力したい場合に名前空間を使用することです。たとえば、私は最近、OmciAttribute、OmciAlarm、OmciMeなどと呼ばれるいくつかのクラスを作成し、Omciを独自の名前空間に分割する必要があることに気付きました。

1
Karl Bielefeldt