73306


以下のブログでインターフェースについて解説されています。  
が、一点よくわからない所があります。

[継承と委譲の使い分けと、インターフェースの重要性について](https://ikenox.info/blog/inheritance-and-
delegation-and-interface/)

[code]

    interface IUserRepository {
        User getUser(int userId);
        void saveUser(User user);
    }
    
    // 実装クラス
    class UserRepository implements IUserRepository{
    
        Database database;
    
        UserRepository(Database database){
            this.database = database;
        }
    
        User getUser(int userId) {
            String sql = String.format("SELECT * FROM users WHERE user_id=%d", userId);
            // ...
        }
    }
    
    // 実行クラス
    class SomeApplicationService { 
        IUserRepository userRepository;
    
        void changeUserEmail(String email){
            User user = userRepository.getUser(userId);
            user.setEmail(email);
            userRepository.saveUser(user);
        }
    }
    
[/code]

上記の例では、実行クラスで `IUserRepository userRepository` を宣言し、  
changeUserEmailメソッドで `userRepository.getUser(userId);` と実行しています。

しかし、よく見るインターフェースの解説だと、changeUserEmailメソッドで  
`IUserRepository userRepository = new UserRepository ();`  
として実装クラスのインスタンスを作ってから、  
`userRepository.getUser(userId);` を実行すると思うのですが、

**上記の例（実行クラスで`IUserRepository userRepository`を宣言して使う）というのは、  
どういった仕組みでインターフェースを使っているのでしょうか？**

**また、  
もし、２つ目の実装クラス`UserRepository2`みたいのが出来た場合、  
`UserRepository` と `UserRepository2` のどちらの実装が使われるかを  
実行クラスでどうやって判別すればよいでしょうか？**

このようなインターフェースの使い方は他でも見たことあるので、文法自体は間違っていないと思われるのですが、理解がむずかしくハマっています。

* * *

**追記**

例えば、以下のspring
bootサンプルコードでもControllerからインターフェースを呼んでいますが、どの実装クラスを使っているかは指定していないです。この仕組みが良くわかりません。

<https://github.com/alexmanrique/spring-boot-application-
example/blob/master/src/main/java/com/myapp/controller/CarController.java>


CC BY-SA 4.0
2021-01-14T08:14:59.423
73288
2021-01-21T04:47:47.003
2021-01-21T04:47:47.003
7277
7277
question
java spring spring-boot
Java（spring boot） インターフェースをnewしないで使う記法が理解できない


`new`しないと使えません。

参照ページのコードは、そのまま動くことは想定されていないのでしょう。誰かが `SomeApplicationService#userRepository`
に具体的なクラスのインスタンスを代入しないと、`changeUserEmail()` は `NullPointerException`で落ちます。


CC BY-SA 4.0
2021-01-14T09:21:54.513
73290
2021-01-14T09:21:54.513
3475
73288
answer


> 上記の例（実行クラスでIUserRepository userRepositoryを宣言して使う）というのは、  
>  どういった仕組みでインターフェースを使っているのでしょうか？

そのようなJavaのサンプルコードでは、setterやコンストラクタが省略されていることが多いので、適宜補完して読み替える必要があります。

[code]

    class SomeApplicationService { 
        IUserRepository userRepository;
    
        // 実際にはコンストラクタや、
        public SomeApplicationService(IUserRepository userRepository) {
            this.userRepository = userRepository;
        }
        // setter が備わっていると考える
        public void setUserRepository(IUserRepository userRepository) {
            this.userRepository = userRepository;
        }
        ...
    }
    
[/code]

これらのメソッドは、適切なタイミングで誰かによって呼び出されている想定で読み進めることになります。  
Spring BootなどのDI framework上で動作させるのであれば、「誰か」というのはframeworkということになるでしょう。

> また、もし２つ目の実装クラスUserRepository2みたいのが出来た場合、  
>  UserRepositoryとUserRepository2のどちらの実装が使われるかを  
>  実行クラスでどうやって判別すればよいでしょうか？

Springのタグが付いているのでそちらの実装で説明すると、利用可能な実装クラス(component)は起動時に一覧化されます(component
scanning)。  
このとき複数のcomponentが見つかればエラーになります(起動しません)。

この場合、コード上で明示的にcomponentに印を付けておき、どちらのcomponentを利用するか明示する必要があります。 具体的には、

  * どれかひとつに[`@Primary`](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-autowired-annotation-primary)が付いていればframeworkはそれを利用する
  * [`@Qualifier`](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-autowired-annotation-qualifiers)で、利用したいcomponentのqualifierを指定する

といった実装を行うことになります。

> 例えば、以下のspring
> bootサンプルコードでもControllerからインターフェースを呼んでいますが、どの実装クラスを使っているかは指定していないです。この仕組みが良くわかりません。

当てはまるクラスが1つだけの場合はそれが利用されます。  
(前述の通り、複数ある場合はエラーになります)

* * *

(コメントより)

>
> SpringのDIでinterfaceの実装クラスが２つある場合にエラーになるのだとすると、Interfaceの説明で良く言われる「実装クラスが増えたとしても、呼び出し元はそれを意識しないで済むので便利」というメリットを享受できない

大抵の場合、プロダクションコード上でインジェクション対象は唯一ですが、にもかかわらず別の実装で挿げ替えられるようにするのは次のような状況を想定しているためです:

  * ユニットテストでインジェクション対象をモック化する 
    * フレームワークを使わない(「誰か」は自分なのでframeworkのルールに従わず挿入できる)
    * component scanning対象の操作(例えばクラスパスの変更によって)
  * プロダクション環境とは異なる環境(例えばローカルの開発環境)で実行するための実装切り替え 
    * component scanning対象の操作(例えば`ACTIVE_PROFILES_SPIRNG`環境変数によって)

簡単に言うと、実装は確かに複数用意しますが、それらの内どれが実際にインジェクションされるべきかは **起動時に** 指定するので問題になりません。

(以下、余談気味になりますが)  
他方、プロダクションコード上に複数実装を用意しておき、起動時でなく **実行中に** 実装を挿げ替えたい、というような場合も無くは無いでしょう。  
そのような場合には、ここまでに登場したようにDIをそのまま使うのではなく、 Service Locator Pattern
(適切な説明が見つからなかったので[Google検索結果リンク](https://www.google.com/search?q=service%20locator%20pattern))などで実現することになるかと思います。

次のリンクにサンプル実装があります:

  * [Annotation based ServiceLocatorFactoryBean?](https://stackoverflow.com/a/33993699/4506703) \- Stack Overflow

この例では、 `@Bean(name = "jsonParser")`, `@Bean(name = "xmlParser")`
という指定で名前を付けておき、利用時に名前を指定することで、どちらを利用するかを明示しています。  
この場合は、そもそもインジェクションの仕組みを直接利用しているわけではない(`Parser`を`@Autowired`しているわけではない)ので問題になりません。


CC BY-SA 4.0
2021-01-14T23:57:00.037
73306
2021-01-17T00:35:15.807
2021-01-17T00:35:15.807
2808
2808
73288
answer


まず、ご呈示のサンプルはきちんと動作します。

そのうえで「複数ある場合動作しない」とinterfaceの利用価値の両立について

・interface は仕様と実装を分ける意味で効果的⇒その通り  
・（自動インジェクトを指定している場合）複数候補があるとエラー⇒おそらくその通り  
・複数ある場合柔軟に選択できるべきでは？という疑問⇒その通り  
・２つは矛盾する⇒しない

というのも、「自動でインジェクトする（ワイアする）」ことを前提とすれば「複数ある」場合どちらをインジェクトすればいいのかわからない⇒だからエラー。ですが、「自動でインジェクトすること」は強制されていません。コーディングする人が任意にインジェクトするオブジェクトを指定可能です。

そもそも、インジェクトするオブジェクトはプログラマがユニークになるように差配するのが普通です。たとえば、それはapplicationContext.xmlで解決することだったり、ほかの方がおっしゃるように、@Qualifierを利用することだったりします。  
しかし、「将来のためにinteface使っておいても、普通は１つデフォルト作ればいいよね」⇒「だったら自動でインジェクトしたほうが楽じゃね？」⇒「そういう仕組みを作ろうぜ」の流れで追加されていて、機能の目的として「主従」にわけるなら従になります。

また、自動で決定する場合には大きく

・ユニークに特定できる場合それを利用し、それ以外はエラー  
・命名規約（例えばDefault+<interface名>）でデフォルト解決する

の２つの方法が挙げられますが、Springは前者を採用しているのですね。（ぱっとみ後者の仕掛けを説明しているサイトがなかっただけなので、本当はあるのかもしれません。）

どっちが正でどっちが悪という話でもなく、状況に合わせて使えばよいのだと。


CC BY-SA 4.0
2021-01-16T00:41:50.747
73332
2021-01-16T00:58:39.443
2021-01-16T00:58:39.443
10174
10174
73288
answer