Başlık "Dairesel Bağımlılık" diyor, ancak doğru ifade değil, çünkü bana göre tasarım sağlam görünüyor.
Bununla birlikte, mavi parçaların dış ortaktan verildiği ve portakalın kendi uygulamam olduğu aşağıdaki senaryoyu düşünün. Aynı zamanda birden fazla olduğunu varsayalım ConcreteMain
, ama belirli bir tane kullanmak istiyorum. (Gerçekte, her sınıfın biraz daha bağımlılıkları var, ama burada basitleştirmeye çalıştım)
Tüm bunları Depency Injection (Unity) ile başlatmak istiyorum, ancak Açıkçası StackOverflowException
aşağıdaki kodda bir tane alıyorum , çünkü Runner ConcreteMain'i başlatmaya çalışıyor ve ConcreteMain'in bir Runner'a ihtiyacı var.
IUnityContainer ioc = new UnityContainer();
ioc.RegisterType<IMain, ConcreteMain>()
.RegisterType<IMainCallback, Runner>();
var runner = ioc.Resolve<Runner>();
Bundan nasıl kaçınabilirim? Bunu DI ile kullanabilmem için yapılandırmanın bir yolu var mı? Şu anda yaptığım senaryo her şeyi manuel olarak kuruyor, ancak bu ConcreteMain
onu başlatan sınıfta sert bir bağımlılık yaratıyor. (Yapılandırmada Unity kayıtları ile) kaçınmaya çalışıyorum budur.
Aşağıdaki tüm kaynak kodları (çok basitleştirilmiş örnek!);
public class Program
{
public static void Main(string[] args)
{
IUnityContainer ioc = new UnityContainer();
ioc.RegisterType<IMain, ConcreteMain>()
.RegisterType<IMainCallback, Runner>();
var runner = ioc.Resolve<Runner>();
Console.WriteLine("invoking runner...");
runner.DoSomethingAwesome();
Console.ReadLine();
}
}
public class Runner : IMainCallback
{
private readonly IMain mainServer;
public Runner(IMain mainServer)
{
this.mainServer = mainServer;
}
public void DoSomethingAwesome()
{
Console.WriteLine("trying to do something awesome");
mainServer.DoSomething();
}
public void SomethingIsDone(object something)
{
Console.WriteLine("hey look, something is finally done.");
}
}
public interface IMain
{
void DoSomething();
}
public interface IMainCallback
{
void SomethingIsDone(object something);
}
public abstract class AbstractMain : IMain
{
protected readonly IMainCallback callback;
protected AbstractMain(IMainCallback callback)
{
this.callback = callback;
}
public abstract void DoSomething();
}
public class ConcreteMain : AbstractMain
{
public ConcreteMain(IMainCallback callback) : base(callback){}
public override void DoSomething()
{
Console.WriteLine("starting to do something...");
var task = Task.Factory.StartNew(() =>{ Thread.Sleep(5000);/*very long running task*/ });
task.ContinueWith(t => callback.SomethingIsDone(true));
}
}