なぜSpring DIを使うのか
スプリングフレームの代表的な技術の一つである依存注入(DI)について説明する.
なぜDIという技術が現れたのか.そして、この記事では使用後に得られるメリットをまとめています.
注入依存関係、注入依存性 クライアントがどのサービスを使用するかを示すのではなく、クライアントがどのサービスを使用するかを指定します. 「注入」は、使用するオブジェクト(クライアント)に依存性(サービス)を渡すことを意味する
理解を助けるために、各クラスの詳細な機能を実現するのではなく、上記のクラス図を参照してコードのコア部分を説明します. MemberServiceImplは、格納メンバーのRepositoryをJDBCとして使用します. が突然JDBC->JPAに変更されました. はインタフェースを設計した自分自身に満足し、新しいJpaMemberRepository実装クラスを作成し、適用した.
しかし、このコードには問題があります.
オブジェクト向け設計の原則に反するコード
オブジェクト向けの設計原則ではSRP,OCP,DIPに違反している.
これらの原則を簡単に説明します. クラスは1つの責任しか負いません. ソフトウェア要素は拡張時に開いていますが、変更時には閉じている必要があります. の具体化ではなく抽象化に頼る. クライアントコードは、実装クラスに依存せず、インタフェースに依存すべきである. では、上記のコードのどの部分がOCP、DIP、SRPに違反しているかをよく見てみましょう.
SRP違反 クライアントコードは、独自の論理を実行するだけでなく、依存関係の責任にも関心を持っています.
DIP違反 抽象(インタフェース)とともに、特定の(実装)クラスにも依存する. 抽象依存:MemberRepositor :JdbcMemberRepository,JpaMemberRepositor に依存する.
OCP違反 は、新しいニーズに対応して機能を拡張し、クライアントコードも変化しました. まとめると、クライアントコードには多くの責任があり、インタフェースだけでなく、具体的なクラスも知っています.そのため、機能拡張が発生すると、ソースコードの変更も発生します.
どうやって問題を解決しますか??
正解は、インタフェースのみに依存するように設計を変更する必要があります.
コンパイルは成功しましたが、実行時にインプリメンテーションボディがないため、NPE(null pointerexception)が生成されます.
では、インタフェースだけに依存するようにどのように設計すればいいのでしょうか.
このため依存注入(DI)概念が出現した.
DIの目的は
すなわち,クライアントコード内部に依存関係を設けず,関心事項を外部に分離する.
前の問題を解決するために新しいクラスを作成します.
アプリケーション全体の動作を構成するために、実装オブジェクトを作成および接続する責任と役割を持つクラス.インプリメンテーションオブジェクトの作成 MemberServiceImpl JdbcMemberRepository 作成者注入によって作成されたオブジェクトインスタンス参照 MemberServiceImpl -> JdbcMemberRepository 次に、クライアントコードMemberServiceImplに依存注入されたジェネレータを作成します. MemberServiceImpl(クライアントコード)では、どのようなインプリメンテーションが注入されるか分かりません. 生成器を介してどのインプリメンテーションボディを注入するかはAppConfigによって決定される. MBERServiceImpl(クライアントコード)は、リレーションシップに依存せず、実行に専念します(ビジネスロジック)
注意:finalキーワードは、宣言とともに初期化されたポイントと再割り当てを阻止するために使用されます.
以前のようにJDBC->JPAに変更した場合?
AppConfigを変更するだけです. https://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EC%84%B1_%EC%A3%BC%EC%9E%85 https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8
なぜDIという技術が現れたのか.そして、この記事では使用後に得られるメリットをまとめています.
DIとは何ですか。
注入
DI出現背景
理解を助けるために、各クラスの詳細な機能を実現するのではなく、上記のクラス図を参照してコードのコア部分を説明します.
public class MemberServiceImpl implements MemberService {
MemberRepository memberRepository = new JdbcMemberRepository();
@Override
public void join(Member member) {
memberRepository.save(member);
}
}
public class MemberServiceImpl implements MemberService {
MemberRepository memberRepository = new JpaMemberRepository();
@Override
public void join(Member member) {
memberRepository.save(member);
}
}
多形性を利用して、インプリメンテーションのみをJpaMemberRepositoryに変更して、何の問題もないようで、よく動いています!しかし、このコードには問題があります.
オブジェクト向け設計の原則に反するコード
オブジェクト向けの設計原則ではSRP,OCP,DIPに違反している.
これらの原則を簡単に説明します.
SRP 단일 책임 원칙
(Single Responsibility Principle) OCP 개방-폐쇄원칙
(Open/Closed Principle) DIP 의존관계 역전 원칙
(Dependency Inversion Principle) MemberRepository memberRepository = new JdbcMemberRepository();
MemberRepository memberRepository = new JpaMemberRepository();
SRP違反
DIP違反
OCP違反
new JdbcMemberRepository() -> new JpaMemberRepository()
どうやって問題を解決しますか??
正解は、インタフェースのみに依存するように設計を変更する必要があります.
public class MemberServiceImpl implements MemberService {
MemberRepository memberRepository;
@Override
public void join(Member member) {
memberRepository.save(member);
}
}
体現体new JpaMemberRepository()
はキャンセルされ、界面のみに依存するようになった.コンパイルは成功しましたが、実行時にインプリメンテーションボディがないため、NPE(null pointerexception)が生成されます.
では、インタフェースだけに依存するようにどのように設計すればいいのでしょうか.
누군가 클라이언트 MemberServiceImpl에 MemberRepository 구현체를 대신 생성하고 주입
にします.このため依存注入(DI)概念が出現した.
興味の分離-(AppConfig)
DIの目的は
관심사를 분리
を作ることです.すなわち,クライアントコード内部に依存関係を設けず,関心事項を外部に分離する.
前の問題を解決するために新しいクラスを作成します.
アプリケーション全体の動作を構成するために、実装オブジェクトを作成および接続する責任と役割を持つクラス.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public MemberRepository memberRepository() {
return new JdbcMemberRepository();
}
}
AppConfigというクラスが作成されました.public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
}
注意:finalキーワードは、宣言とともに初期化されたポイントと再割り当てを阻止するために使用されます.
class MemberServiceTest {
MemberService memberService;
@BeforeEach
public void beforeEach() {
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
}
@Test
void join() {
Member member = new Member(1L, "lee");
memberService.join(member);
...
}
}
テストコードは次のとおりです.AppConfigで依存性を得ることができます.以前のようにJDBC->JPAに変更した場合?
AppConfigを変更するだけです.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public MemberRepository memberRepository() {
return new JpaMemberRepository();
}
}
References
Reference
この問題について(なぜSpring DIを使うのか), 我々は、より多くの情報をここで見つけました https://velog.io/@roro/DI-Dependency-Injection-사용이유テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol