目次
1: インターフェースまたは抽象クラスを使用する
// 接口或抽象类
public interface ServiceA {
void methodA();
}
public interface ServiceB {
void methodB();
}
// 实现类
public class ServiceAImpl implements ServiceA {
private ServiceB serviceB;
public ServiceAImpl(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void methodA() {
// 使用ServiceB的方法
serviceB.methodB();
}
}
public class ServiceBImpl implements ServiceB {
private ServiceA serviceA;
public ServiceBImpl(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void methodB() {
// 使用ServiceA的方法
serviceA.methodA();
}
}
この例では、ServiceA
および はServiceB
それぞれインターフェイスを定義し、その後ServiceAImpl
、 および はServiceBImpl
それぞれこれらのインターフェイスを実装します。これらはコンストラクターを通じて相互の依存関係を注入します。
2: コンストラクターのインジェクション
public class ServiceA {
private ServiceB serviceB;
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void methodA() {
// 使用ServiceB的方法
serviceB.methodB();
}
}
public class ServiceB {
private ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void methodB() {
// 使用ServiceA的方法
serviceA.methodA();
}
}
この例では、ServiceA
と のServiceB
クラスがコンストラクターを通じて相互の依存関係を注入します。
3: 依存性注入コンテナーを使用する (Spring)
Spring フレームワークを使用する場合、Spring コンテナーは循環依存関係を自動的に処理できます。以下は、単純な Spring 構成例です。
@Configuration
public class AppConfig {
@Bean
public ServiceA serviceA() {
return new ServiceA(serviceB());
}
@Bean
public ServiceB serviceB() {
return new ServiceB(serviceA());
}
}
この例では、Spring コンテナは、作成時に作成されていることを確認するため、serviceA
およびその逆の循環依存関係を自動的に解決します。serviceB
serviceA
serviceB
これらの例は、循環依存関係を処理するさまざまな方法を示しており、プロジェクトのニーズに合ったものを選択できます。どちらのアプローチを採用する場合でも、潜在的な問題を回避するために、コードが適切に構造化され、依存関係が適切に挿入されていることを確認してください。
他にも次のような方法があります。
4. 遅延初期化
プログラミング言語が遅延初期化 (Java のアノテーションなど@Lazy
) をサポートしている場合は、特定の依存関係を遅延初期化するように設定できます。これにより、循環依存関係が存在する場合でも、オブジェクトは必要な場合にのみ初期化されるため、問題の発生を軽減できます。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@Configuration
public class AppConfig {
@Bean
@Lazy // 使用@Lazy注解延迟初始化ServiceA
public ServiceA serviceA() {
return new ServiceA();
}
@Bean
@Lazy // 使用@Lazy注解延迟初始化ServiceB
public ServiceB serviceB() {
return new ServiceB();
}
}
public class ServiceA {
private ServiceB serviceB;
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void methodA() {
// 使用ServiceB的方法
serviceB.methodB();
}
}
public class ServiceB {
private ServiceA serviceA;
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void methodB() {
// 使用ServiceA的方法
serviceA.methodA();
}
}
この例では、@Lazy
アノテーションを使用して Bean 定義をマークしserviceA
、serviceB
Spring コンテナーにそれらを遅延初期化するように指示します。このようにして、循環依存関係がある場合でも、オブジェクトは必要な場合にのみインスタンス化されるため、循環依存関係によって引き起こされる問題が回避されます。
注釈は@Lazy
通常 Spring コンテナーで使用されるため、使用する前にプロジェクトが Spring フレームワークを統合していることを確認してください。
5. 工場出荷時のパターンを使用する
public class ServiceA {
private ServiceB serviceB;
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void methodA() {
// 使用ServiceB的方法
serviceB.methodB();
}
}
public class ServiceB {
private ServiceA serviceA;
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void methodB() {
// 使用ServiceA的方法
serviceA.methodA();
}
}
public class ServiceFactory {
private ServiceA serviceA;
private ServiceB serviceB;
public ServiceA createServiceA() {
if (serviceA == null) {
serviceA = new ServiceA();
serviceA.setServiceB(createServiceB());
}
return serviceA;
}
public ServiceB createServiceB() {
if (serviceB == null) {
serviceB = new ServiceB();
serviceB.setServiceA(createServiceA());
}
return serviceB;
}
}
この例では、オブジェクトのServiceFactory
作成を担当するファクトリ クラスを導入します。またはを作成する必要がある場合、ファクトリ メソッドはオブジェクトが既に存在するかどうかを確認し、存在する場合は既存のオブジェクトを返し、存在しない場合は新しいオブジェクトを作成します。このように、ファクトリ メソッドは、オブジェクトが必要な場合にのみ相互に参照するため、オブジェクトの作成時に循環依存関係が確実に解決されるようにします。ServiceA
ServiceB
ServiceA
ServiceB
ファクトリ メソッドを使用すると、オブジェクトの単一インスタンスの性質を維持しながら、循環依存関係の問題を効果的に処理して、パフォーマンスとリソースの使用率を向上させることができます。