質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.01%

javaで実装上特に不要だがinterfaceを継承する設計

解決済

回答 7

投稿 編集

  • 評価
  • クリップ 4
  • VIEW 4,106
退会済みユーザー

退会済みユーザー

仮にAというinterfaceを作りそれを仮にBというクラスが継承したとします。Bのインスタンスを仮にCクラスのメソッドsetA(A a)というメソッドでCのメンバー変数にAクラスとしてセットします。コードにすると雑ですが、下記みたいな感じでしょうか。

interface Aは実装上なくても問題ないしむしろ邪魔に思えるのですが、CがBのインスタンスをAとして扱えるために余計なBのメソッドを呼べないので疎結合だからいいのだそうです。私は勉強不足の為わかった様なわからんような気分なんですが、interfaceはある程度、活用性がないと作る意味ない気がします。例えばD,E,Fのクラスがあってそれらも、Aのinterfaceを継承して他のクラスに使わせるならわかる気がします。でも、Bのみしか継承しないのだったらいらないと思うのです。

こういうのはリファクタリングのテクニックなんですか。そんなに重要なんでしょうか。テクニックの名前とかありますか。

interface A {}

class B implements A {}

class C {
    A a;
    void setA(A a) {
        this.a = a;
    }
}

~~~~
   B b = new B();
   C c = new C();
   c.setA(b);
~~~~
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 7

checkベストアンサー

+3

余計なメソッドを呼べなくするのが疎結合なわけではないです。
メソッドを公開したくなければ、privateにすればいいだけなので。

疎結合とは、依存関係がない、というものです。
依存とは、import文であったり、new と書いている部分のことです。

ようは、「そのクラスが削除されたとしても、コンパイルエラーにならない」
という関係が疎結合です。

この例でいうと、Bクラスが消えても、Cクラスには影響がないということです。

つまりインターフェースを使った設計にしておくと、
呼び出し元に影響を与えずに、
必要なものはそのインターフェースを実装して追加すればいい、
不要なものは削除すればいいようになるところが嬉しいのです。

逆の密結合は、仕様変更や拡張に非常に弱く、一部のプログラムを直すだけで、
そこら中をテストし直す必要があったりと、大手術になることが多いです。

例えばD,E,Fのクラスがあってそれらも、Aのinterfaceを継承して他のクラスに使わせるならわかる気がします。

そうですね。その通りだと思います。
なので、普通はyubaさんのおっしゃっていることが多いです。
今後増えることを想定としているため、インターフェースを決めている。ということです。

悪い例

public class PC {
    public void setKeyboard(Keyboard keyboard) {};

    public void setMouse(Mouse mouse) {};
}

public class Keyboard {}

public class Mouse {}

良い例

public class PC {
    public void setUsbDevice1(USB usb) {};

    public void setUsbDevice2(USB usb) {};

    public void setUsbDevice3(USB usb) {};
}

public class Keyboard implements USB {}

public class Mouse implements USB {}

現実の世界でも、周辺機器が増えたからPCに修理がいるというのは不便なわけです。

【悪い例】
プリンターを買ったから、PCにプリンタ用の穴(setPrinter)をつけてもらうように修理に出す。

【良い例】
プリンターを買ったけど線がUSBだったから、そのままPCに接続できた。
PCの修理は不要。

周辺の部品が、使う側に影響を出さないという設計がいいんです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/21 17:53 編集

    なるほどです。後で変更を加えるときの作業で影響範囲が少なくなるので、今後の事を考えると疎結合で実装するのがいいって感じでしょうか。後、削除してもコンパイルエラーにならないという事は全く考えたことなかったのですごい納得しました。ご回答ありがとうございました。

    キャンセル

+2

A,B,Cクラスを作るのが別々の人だとしたらどうでしょう?
Cクラスの作者とAクラスの作者は並行して別々に開発します。あとで結合することを考えればCの作者は「どんなクラスを作ってもいいけどBインターフェイスとして実装してくれ」とあらかじめ頼んでおけばいいわけです。

これは特殊なケースではありません。ライブラリを作る場合、ライブラリ作者がA,Cの作者にあたり、利用者がB作者に当たることになります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/21 17:50

    なるほど、チーム開発だとかなり大事そうですね。それぞれのクラスが密接だと変更が大変。また、ライブラリーだとインターフェイスが必要なわけですね。なんかわかってきた気がします。ご回答ありがとうございました。

    キャンセル

+1

回答としては、典型的ですが、TPOによります。
設計規模、実装内容、納期、要件様々な要因によって、実装内容が変わります。

また、
デザインパターンとしてよく言われる議論の1つでもありますが、
初めのうちは以下の理由から今すぐに理解できなくてもよいと存じ上げます。
熟練者もしくは、webサイトで発信している方のコードを見るなどの癖はつけるようにしてください。

  1. そもそも必要性に迫られたことがない。(学習中であればなおのことわかりませんよね)
  2. フレームワークを利用、実装を想定した、学習するときにありがたみに気づくことがあります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/17 00:43

    自分は学習中だった書籍を何度か腑に落ちるまで読み直し、何度か同じようなコードを書いたことでふとした時に気づきました。現在も鋭意精進中です。

    キャンセル

  • 2016/03/17 00:50 編集

    ご回答ありがとうございます。

    実はこれでも3,4年近くにJavaに触っていたりします(笑)
    ただ、リファクタリング!?と呼ばれるものを全く勉強したことないので、初心者マークで質問させていただきました。
    確かに、ご教示頂いた、理由に関してはまだ経験したことないかもしれないので今後はっきりと理解するのかもしれないです。

    参考サイトありがとうございました。

    キャンセル

  • 2016/03/17 00:56

    興味が出たことは大変良い兆候だと思います。
    僕も所持はしていますが、いかにリファクタリングに関する書籍が結城先生であります。
    http://www.hyuki.com/dp/
    手にとってみてはいかがでしょうか。

    キャンセル

  • 2016/03/21 18:06

    ありがとうございます。これ思い切って買います。

    キャンセル

+1

リファクタリングというより、テクニックでしょうか。

知っている中では、Immutable Interface(イミュータブル・インタフェース)という手法と本質は同じだと思います。
下記のようなインタフェースとそれを実装したクラスがあったとします。
関数の戻り値などで、ImmutableA型を返すか、A型を返すかによって、権限機能(編集できる権限、閲覧のみの権限)などに応用できます。
(といっても、ImmutableA型をA型にキャストするような使い方をされると意味ないので、実装する側が間違えないようにするための工夫だと思ってます。
Immutable Interfaceに関して詳しい方居ましたら補足お願いしたいです。)

// インスタンスの内容を読み取り専用にするインターフェース
Public Interface ImmutableA{
  public String getName();
  public int getNum();
}
Public class A immplements ImmutableA{
  private String name;
  private int num;

  public String getName() {return name};
  public int getNum() {return num };
  public void setName(String name) { this.name = name; }
  public void setNum(String num) { this.num = num}
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/30 00:53

    ご回答ありがとうございます。Immutable Interfaceとは、初めて聞きました。勉強になります。

    キャンセル

+1

例にあるようなパターンの場合は、多分不要なでしょうね。

Bを渡すのに、Aを引数とするメソッドを定義している場合、いくつかの理由が考えられます。

例えば、Iteratorパターンがそうで、B以外にもCを使って似たようなことをしたいクラスが複数あり、Cで共通して使いたいメソッドをまとめたものをAとして定義した場合です。

または、例のコードとは違いますが、FactoryMethodパターンの場合にはありえます。実際のクラスを隠してわたす場合で、Bの状態変更をパッケージ内に限定したい場合などにも有効です。

Rubyやjavascriptはインターフェイスを持っていないので、実はそれほど大事なテクニックでも無いかもしれません。ですが、私は使う必要のないメソッドを晒して使う側を混乱させないようにするには良い方法だと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/30 00:49

    ご回答、ありがとうございました。こんな〜〜パターンみたいな物があったんですね。勉強になりました。

    キャンセル

  • 2016/03/30 16:29

    他にも書いてる人がいますが、りこれらのパターンをデザインパターンと言います。
    リファクタリングの際に、「ここはFactortMethodパターンをを導入しよう」などと話すとリファクタリングの方向性が一言で説明できたりします。テクニック的なものを質問されたと考えたので書きましたが、違ったと様ですね。

    キャンセル

  • 2016/03/30 21:25

    すいません。質問が曖昧でした。一番知りたいのは何の為にというところでした。
    ただ、そう言った具体的なテクニック名などもあるのであれば知りたかったので助かりました。

    キャンセル

+1

疎通性ではなく疎結合ではないでしょうか?
共起語としては DI なんかでぐぐるとよいかも。
あとリファクタリングのテクニックとは言わないような… (別の用語を混ぜて覚えている??

よくある目的は、実装を交換可能にすることです。

実装を交換可能にすると

  1.  A と C が汎用的な機能であれば、再利用性があがる。
  2.  A が C に対し必要最小限の機能で構成されている場合、可読性が上がり理解しやすいコードになる。
  3.  目的に合わせて A の実装 (B その他クラス) を入れ替えることができる。

などが良い感じです

↑ 3. の補足ですが、例えば性能特製によって目的ごとに実装を交換するだとか
本番コードとテストコードを入れ替えやすいとかですかね

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/17 09:10

    ご回答ありがとうございます。確かに疎結合と言われていた気がします。そしてこれは、DIコンテナーのテクニックなんですか。テストコードを使ったりする時に便利なんですね。

    キャンセル

+1

結果的に不要だっただけで、先にinterfaceAと受け入れクラスCを作って、全体を作ってから、差し込むBを作ったのだけど、実際は1つのクラスでしか使わなかった・・という感じだと、そうなります。

最終的に無駄なら削っていいわけなのですが、他人のソースコードを読むときには、どうやって作っていったのだろう・・という視点がないと何をしているのかわからないことがあります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/21 17:55

    後の事を考えると必要って事ですね。ご回答ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.01%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる