هدف از factory pattern را می توان جدا کردن استفاده از یک component خاص ، انتخاب پیاده سازی component و مدیریت component نمونه دانست. Abstract factory برای ایجاد امکان switch کردن بین پیاده سازی های متفاوت factory ها با component های متفاوت در زمان اجرا استفاده می شود و این نقص در static factory ها را از بین می برد. برای حل مشکل وابستگی مستقیم به وسیله این روش در ابتدا یک factory رو در اختیار می گیریم و سپس component های اون رو درخواست می کنیم. نمونه کدهای زیر مرا حل این روش رو نشون میده:
public class MyClass {
IMyComponent component = null;
public MyClass() {
IMyComponentFactory factory =
MyComponentFactoryManager.getFactory("A");
component = factory.instance();
}
public void myMethod(){
component.doSomething();
}
}
اینترفیس و کلاس متناظر به این صورت تعریف می شوند:
public interface IMyComponentFactory {
IMyComponent instance();
}
public class MyComponentFactoryManager {
private static Map<String, IMyComponentFactory> factories =
new HashMap<String, IMyComponentFactory>();
public static setFactory(String factoryId, IMyComponentFactory factory){
factories.put(factoryId, factory);
}
public static IMyComponentFactory getFactory(String factoryId){
return factories.get(factoryId);
}
}
همانطور که می بینیم اکنون امکان تعویض factory ها در زمان اجرا وجود دارد اما همچنان factory id به صورت hard code در کلاس MyClass وجود دارد. همچنین MyClass برای بدست آوردن یک نمونه IMyComponent به کلاس MyComponentFactoryManager واینترفیس IMyComponentFactory نیاز دارد. در واقع تمام اون چیزی که MyClass بهش نیاز دارد IMyComponent هستش ولی حالا نیاز به شناخت یک کلاس و اینترفیس اضافی دارد.
وقتی از dependency injection استفاده می کنیم مسئولیت بدست اوردن نمونه های مورد نیاز به یک container داده شده و تزریق وابستگی ها از بیرون کلاس صورت میگیرد. در زیر مشاهده می کنیم که Myclass هنگام استفاده از dependency injection به چه شکل خواهد بود (تزریق وابستگی به وسیله Constructor)
public class MyClass {
IMyComponent component = null;
public MyClass(IMyComponent componentImpl) {
component = componentImpl;
}
public void myMethod(){
component.doSomething();
}
}
در اینجا نیازی به شناخت کلاس و اینترفیس اضافی نخواهیم داشت و پیچیدگی کد کاهش می یابد.
در یک IOC container مثل spring شما به راحتی می توانید چندیدن bean و وابستگی بین آنها را تعریف می کنید
<bean id=”myComponentA” class=”com.javabyab.di.MyComponentA”/>
<bean id=”myClassA” class=” com.javabyab.di.MyClass”>
<constructor-arg ref=” myComponentA”/>
</bean>
<bean id=”myComponentB” class=”com.javabyab.di.MyComponentB”/>
<bean id=”myClassB” class=” com.javabyab.di.MyClass”>
<constructor-arg ref=” myComponentB”/>
</bean>
نهایتا یک نمونه از کلاس Myclass را container به برنامه تزریق می کند.
MyClass myClassInstance = container.getBean("myClassA", MyClass.class);