• 締切済み

誘導可能なコンポジションの循環参照について。

Javaの設計についての基本的な質問です。 企業を表すCompanyクラスのフィールドに、そこで働く従業員を表すEmployerクラスのSetを保持していたとします。 Employerクラスは自身の所属するCompanyを取得するためのメソッドgetCompany()を持っていたとします。 public class Company{   Set<Employer> employers; } public class Employer{   public Company getCompany(){   } } 実現したいのは「従業員から自身の所属する企業を知る」ということです。 このgetCompany()を実現するためにはEmployerのフィールドに所属するCompanyのインスタンスを保持することになると思います。 また、特にDIなどは考えないとすると、Employerクラスのインスタンス生成時等には所属するCompanyクラスのインスタンスを渡すなどの必要があります。 上記のようにすれば実現自体は可能なことはわかるのですが、循環参照のような形となり適切でないような気がします。 Company has employers. は正しいと思いますが、 Employer has a company. は何か違う気がします。 EmployerのコンストラクタにCompanyを渡して、生成したEmployerをそのCompanyにaddするのも不自然に感じます。 これらを実現するためにはどのような形が適切と言えるのでしょうか。 上記は最も正しい・美しい形といえるのでしょうか。 そもそも何か根本的なところが誤っていますでしょうか。 これはあくまで例ですが、回答いただくには情報が足りないのであればご指摘ください。 結果、 http://okwave.jp/qa/q2652715.html こちらの質問と全く同じになってしまいましたが、Javaでも同様でしょうか。

みんなの回答

回答No.2

NO.1 にも書きましたが DIP を使うという手段もあります。 組織の骨組み(構造)を定義するパッケージを 一つも設け、Employee や Company はそこで インターフェースとして定義します。 本当の Employee や Company はインターフェースを実装します。 こうすると、インターフェース間の相互参照は残りますが、 クラス間の相互参照は消えてしまいますので好きなパッケージで Employee や Company 実装することが可能になり、jarの相互残照 などが起こることも無くなります。 Employee や Companyの具象クラスが様々なパッケージに 分散するようでしたら、検討してみるべきです。

全文を見る
すると、全ての回答が全文表示されます。
回答No.1

has は相手を「所有する」強い依存関係ですが、 Employee から Company への関係はもっと弱い より「一般的な依存関係」です。 この区別を学びましょう。 相互参照は注意すべきですが、Java は 相互参照を認めている言語なので そう神経質になることはないでしょう。 ただ、jarを超えて循環参照などはできないので そういう時は DIPなどを使うことになると思います。

mmmosa
質問者

お礼

ご回答ありがとうございます。 依存関係の強度についてあまり考えていませんでした。 勉強してみます。 ただどうしても相互参照に起因する不整合のリスクが発生してしまうのが心配です。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • マルチスレッド下でのインスタンス変数・クラス変数

    よろしくお願いします。  マルチスレッド下で動作するクラスを作成しています。データにアクセスするためのオブジェクトを クラスのフィールド値として保持し、使い回しを行いたいと考えています。このデータアクセスオブジェクト(以下Dao)内では特にフィールドは使用せず、全てローカル変数のみで動作するようになっています。Dao自体は初回のクラス生成時にstatic処理にてフィールドにセットされます。  このDaoを保持するフィールドは、staticなクラス変数が良いのか、インスタンス変数として保持する方が良いのか迷っております。  クラス変数ならばPermanent領域をオブジェクト1つ分のメモリ使用で済み、インスタンス変数だとスレッド毎にheapを使い、処理数が増えるとメモリ圧迫しちゃう?と安易に考えてしまったりしています。  ご意見・ご助言よろしくお願い致します。

    • ベストアンサー
    • Java
  • 同一クラスインスタンス名で別クラスのインスタンス作成方法(C++)

    下記ソース(Java)の処理をするような、C++の実装方法を教えていただきたいです。 【処理内容】 クラスBのインスタンスを保持しており、クラスBのインスタンス名と同一であるクラスAのインスタンス生成 ClassA A_Instance = (ClassA)Class.forName(B_instance.name).newInstance(); 要はクラスインスタンスの名前の求め方がわからないのです。それさえわかれば、newしてクラスポインタを返すメソッドを用意すれば何とかなると考えていますが。 ※C++のAPI一覧はどこにあるのだろうか・・・

  • 動的に生成されるインスタンス間のやりとりについて

    あるクラスのインスタンスが動的に複数生成される状態で,一つのインスタンスから, 複数の他インスタンスのメンバ関数(仮に関数A)を呼びたいと考えています. そこでstaticなインスタンスのリストのようなものを設けようと考えました. 各インスタンスの関数Aへ関数ポインタの配列を定義し, それによって上記を実現しようと思いました. しかし,インスタンス生成前にインスタンス名を指定して (instance_name_.*p)(); という様に呼べるわけもなく,どう動的にインスタンスのリストを保持するかが思いつきません. 説明が下手ですいません.どなたか教えていただけますでしょうか. よろしくお願いします. 環境 Windows XP, cygwin

  • java のメソッドの使い方について

    現在のjavaの勉強しております。 そこでフィールドについてどうしてもわからないことがあったので質問させていただきます。 他クラスのメソッドを利用したい時、通常インスタンス化を行いますが、下記のようにフィールドに宣言しても、他クラスのメソッドを利用できることに疑問を感じました。 public class Test{ public String show(){     ~~   return null; } } //Testクラスのshowメソッドを呼び出します public class Test2{ private Test test_; public String triaezu(){    String str = test_.show(); ~~   … このようにフィールドにもつ呼び出しとインスタンス化をして呼び出す方式とは一体何が違うのでしょうか? プログラムの先輩方、基礎的なことすぎて申し訳ないのですが、どうかご教授ください。

    • ベストアンサー
    • Java
  • Javaプログラミング インスタンス生成時の疑問

    現在Javaを学習中の者です。 一通り入門編を終えたところで、テトリス自作に挑戦している最中です。 // 利用クラスのインスタンス生成 block = new Block(); field = new Field(); gui = new GUI(field); proc = new Proc(gui, field, block); 本体Tetrisクラスのコンストラクタ内でこのような記述をしております。 ここで疑問に感じたのですが、例えばFieldクラスにguiオブジェクトを渡したいとなった場合、どう対処するのでしょうか。 field = new Field(gui); gui = new GUI(field); これではおそらくguiインスタンス生成前にオブジェクトを渡しているためおかしな事になってしまいますよね? 実際にやりたい訳ではなく、「こうしたいときどうすればいいんだろう」と思っただけなのですが、気になったので質問させて頂きました。 模索しながら作成中のため、記述自体に突っ込みどころがあるかもしれません…。

    • ベストアンサー
    • Java
  • c++でのヘッダーファイルの循環参照

     c++言語においての質問です.  A, Bという二つのクラスを作ったとします.  宣言は.h,実装は.cppで行っています. 【A.h】 class A{ //内容 public: B ConvertB(); }; 【B.h】 class B{ //内容 public: A ConvertA(); };  上のように,クラスAではクラスBを返すメソッド. クラスBではクラスAを返すメソッドを実装したいとします.  しかし,単純に 【A.h】に #include "B.h" 【B.h】に #include "A.h" などとすると当然循環参照になってエラーになりますよね? ...とは言っても, 【A.cpp】や【B.cpp】にインクルードした所で, ヘッダ側でエラーが起きてしまいます.  そこで,私の場合は... 【A.h】の先頭に class B{ConvertAで用いるメソッド}; 【B.h】の先頭に class A{ConvertBで用いるメソッド};  というようにする事でなんとかエラーを避けています.    ...しかし,この方法ではAやBのクラスの定義を修正する場合に, 2つのファイルのヘッダを書き換えなければならなくなります. A, B, C, D...などとクラスが増えていくと, 一つのヘッダーファイルに4つも5つもクラスの定義を書かなければなりませんし, クラスのメソッドの定義を一つ変えようとしただけでも, 複数のヘッダの内容をいじらないといけません.  非常に読みにくいコードになってしまうのです.  そこで,もう少しスマートに実現する方法は無いでしょうか?  JavaやC#を使えば簡単に解決するのですが...ライブラリの関係でC++を使わなければ ならないのです.  もしくは,このような相互変換?のクラスを作る場合はみなさんはどのようにして ヘッダーファイルの循環参照を避けているのでしょうか?  例えば様々な形式の色空間のクラスなどだったら... RGBクラス YCrCbクラス HSVクラス ...など  このようなクラスを作った後で,RGBをYCrCbに変換出来るようにしたり, その逆へも変換出来るようにしたいのです.  それともこのような変換が出来るクラスを作る事は間違っているのでしょうか?    よろしくお願いします.

  • Ruby 特異メソッドのnewが先に実行?

    Rubyのインスタンス生成について質問があります。 通常クラスを定義する場合は class Hoge ; def hello(); pirnt "hello"; end であると思います。 ただ Hoge = Class.new(); でもクラスは定義できるとききました。 ただこの場合Hogeクラスに定義できるのは HogeというClassクラスから作られた特異クラスとしてのHogeに 特異メソッドのみを定義できるということですよね? 通常のインスタンスメソッドは定義できませんよね? ではでは、 hoge = Class.new(); とした場合はどうなるのでしょうか? この場合は Classクラスの純粋なインスタンスとなるのでしょうか? 前者の定義とおなじ仕方ですが代入先が、通常の変数です。 この場合は、クラスオブジェクトとして生成されるのですか? オンラインマニュアルをみたところ 「新しく名前の付いていない superclass のサブクラスを生成します。 superclass が省略された時にはObject のサブクラスを生成します。 名前のないクラスは、最初に名前を求める際に代入されている定数名を検索し、見つかった定数名をクラス名とします。」 とあります。 上記内容は Classクラスの特異クラスとして定義されている特異メソッド(new)です。 これは Class.new()で作られたインスタンスを代入する先が定数であればその定数名と同じクラスを定義しつつそのClassクラスのクラスオブジェクトを生成するという意味合いでまちがいないでしょうか? 上記のとおりであれば hoge =Class.new()の場合は、やはりhogeというクラスを定義することになるのでしょうか? クラス定義は定数でなければならないはずですよね。 ただ実際、 p hoge;として出力すると#とひょうじされています。これはhogeがクラスオブジェクトではなく ただのインスタンスであるということでしょうか? であるならばこの hoge = Class.new()の式のnewはClassクラスオブジェクトに定義された特異メソッドではなく Classクラスに定義されたnewメソッド・・・・・つまりClassクラスに定義されたインスタンスメソッドの方のnewメソッドだとおもうのですが・・・・・・。 つまりこちらのメソッドですね。 「new( ... ) クラスのインスタンスを生成して返します。このメソッドの引数はブロック引数も含め initialize に渡されます。」 ※オンラインリファレンスから参照しました。 しかし 通常メソッドの検索は特異メソッドからはじまりその後クラスのインスタンスメソッド->親クラスのメソッドと 検索して行くとあります。 必ず先に、特異メソッドを実行しているはずだと思うのですが・・・。 やはり特異メソッドnewを実行しているのでしょうか? 長々すみませんが、ご教授ください。

    • ベストアンサー
    • Ruby
  • メソッドが同じオブジェクトのフィールドを参照しません

    <test1.javaファイル> import java.awt.*; public class test1 { //フィールドの定義 public int x = 10; //メソッドの定義 public void drawMoji(Graphics g) { g.drawString("xの値は、" + x, 20, 20); } } <test2.javaファイル> public class test2 extends test1 { //フィールドの定義 public int x = 20; } <mt.javaファイル> import java.awt.*; import java.applet.*; /* <applet code = "mt" width = 300 height = 200> </applet> */ public class mt extends Applet { public void paint(Graphics g) { //インスタンスの作成 test2 t2 = new test2(); //xの値を表すメソッドの実行 t2.drawMoji(g); } } 上記の3つのファイルをコンパイルして、mt.javaファイルをアプレットビュアーで実行したら、"xの値は、20"と表示したいのに、"xの値は、10"と表示されます。t2オブジェクトのフィールドのxの値が20だから、t2.drawMoji(g)で"xの値は、20"と表示されると思うのですが、どうしてこうなるのでしょうか?教えてください。

    • ベストアンサー
    • Java
  • Javaの課題が全くわかりません。

    この前学校からJavaの課題が出まして、全くわかりません。 <テストクラス>(ファイル名:Test.java) <フィールド> なし <メソッド> 1.メインメソッド 「ここからはテストクラスの流れを書きます」 ・アドレスサーチクラスを生成 ・アドレスサーチクラスのInitialize()メソッドを呼ぶ ・アドレスサーチクラスのSearchName()メソッドを呼ぶ ・検索結果を表示する <アドレスサーチクラス>(ファイル名:AddressSearch.java) <フィールド> 1.アドレス配列(3000個分) <メソッド> 2.住所録ファイル入力設定 (メソッド名) public void Initialize() 「ここからはテストクラスの流れを書きます」 ・住所録ファイルから1行目入力 ・1行を各項目に分解 ・アドレスクラスのインスタンスを生成 ・アドレスクラスのインスタンスに分解した各項目を設定 ・アドレス配列にインスタンスを格納 3.氏名検索 (メソッド名) public Address SearchName(String name) 「ここからはテストクラスの流れを書きます」 ・アドレス配列から氏名を探す ・一致した氏名のインスタンスを戻す  一致しない場合、nullを返す 長くなりました。このような条件でプログラムを作るのは私にはあまりわかりませんでした。googleなどで検索してもあまり良い情報がありません。もしこの問題が解ける方がいらっしゃるなら、ぜひアドバイスやプログラムなどを教えてくれたらありがたいです。

  • Ruby言語に関して質問です。

    Rubyで、クラス定義の際の質問です。 通常 cattle= Class.new(); で引数がデフォルトの場合は、Objectクラスのサブクラス生成すると 公式のリファレンスに記述があります。 調べてみると上記コードの場合は,cattleという無名クラスと呼ばれるものになるそうです。 この無名クラスとはYUGUIさんのサイトにある http://yugui.jp/images/uploaded/20084013-metaclass.png 右端の列にあるメタクラスと呼ばれるものになるのでしょうか? (無名クラス と メタクラスは同義??) また上記URLの画像からメタクラスはClassクラスのインスタンスであるようです。 ただClass.newで実行される newというクラスメソッドってサブクラスを生成すると いうふうにリファレンスにありますがレシーバであるClassクラスのインスタンスを 返すという記述はありません。 ただ、おそらくメタクラスというのはClassクラスのインスタンスなのだとは思いますが、 この理由はなぜなのでしょうか? もう一点、p Cattle.class();と記述すると Classクラスが返ると思います。これはCattleクラスのClassクラスのインスタンスである ということになるのでしょうか? しかしながらYUGUIさんの画像ではCattleはメタクラスのインスタンスとなっています。 であれば、メタクラスを意味するのでしょうか? 公式リファレンスには、上記に書いたような関係はRubyを扱う際には特に問題ではないとありますが、気になっています。

    • ベストアンサー
    • Ruby
PIXUS TS-8330 印字がかすれる
このQ&Aのポイント
  • TS8330 USERです。コピーの際印字がかすれてしまいます。クリーニングはしましたが、結果は同じです。
  • PIXUS TS-8330の印字がかすれる問題にお困りですか?解決方法を探している方に朗報です。
  • キヤノン製品で印字がかすれる問題に遭遇しましたか?お使いのPIXUS TS-8330でも同様の現象が発生する場合、対処方法をご紹介します。
回答を見る