ชื่อกล่าวว่า "การพึ่งพาหนังสือเวียน" แต่มันไม่ได้เป็นถ้อยคำที่ถูกต้องเพราะสำหรับฉันการออกแบบดูเหมือนจะแข็ง
อย่างไรก็ตามให้พิจารณาสถานการณ์ต่อไปนี้ซึ่งชิ้นส่วนสีน้ำเงินได้รับจากคู่ค้าภายนอกและสีส้มคือการนำไปปฏิบัติของฉันเอง นอกจากนี้สมมติว่ามีมากกว่าหนึ่งConcreteMain
แต่ฉันต้องการใช้เฉพาะ (ในความเป็นจริงแต่ละชั้นมีการพึ่งพาอาศัยกันมากกว่านี้ แต่ฉันพยายามทำให้มันง่ายขึ้นที่นี่)
ฉันต้องการเริ่มต้นทั้งหมดนี้ด้วย Depency Injection (Unity) แต่เห็นได้ชัดว่าฉันได้รับStackOverflowException
รหัสต่อไปนี้เนื่องจาก Runner พยายามยกตัวอย่าง ConcreteMain และ ConcreteMain ต้องการนักวิ่ง
IUnityContainer ioc = new UnityContainer();
ioc.RegisterType<IMain, ConcreteMain>()
.RegisterType<IMainCallback, Runner>();
var runner = ioc.Resolve<Runner>();
ฉันจะหลีกเลี่ยงสิ่งนี้ได้อย่างไร มีวิธีการสร้างโครงสร้างนี้เพื่อให้ฉันสามารถใช้กับ DI? สถานการณ์ที่ฉันทำอยู่ในขณะนี้คือการตั้งค่าทุกอย่างด้วยตนเอง แต่นั่นทำให้การพึ่งพาอย่างหนักConcreteMain
ในชั้นเรียนที่ทำให้อินสแตนซ์มัน นี่คือสิ่งที่ฉันพยายามหลีกเลี่ยง (ด้วยการลงทะเบียน Unity ในการกำหนดค่า)
รหัสแหล่งที่มาทั้งหมดด้านล่าง (ตัวอย่างง่ายมาก!);
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));
}
}