我有两个班级。学生和SMSSenderMessage。学生依赖于SMSSenderMessage,而SMSSenderMessage依赖于学生。学生和SMSSenderMessage只有一个构造函数。 我想对这两个类使用构造函数注入。
public interface IPerson
{
string GetName();
}
public interface ISenderMessage
{
void Send(string text);
}
public class Student : IPerson
{
private ISenderMessage S;
public string Name { get; set; }
public Student(ISenderMessage s)
{
this.S = s;
}
public void DoSomeThing()
{
//...Some Thing
S.Send("Hello");
}
public string GetName()
{
return this.Name;
}
}
public class SMSSenderMessage : ISenderMessage
{
IPerson P;
public SMSSenderMessage(IPerson p)
{
P = p;
}
public void Send(string text)
{
string message = text + " " + P.GetName();
//Send SMS: message
}
}
现在。如何从Student和SMSSenderMessage创建实例?
答案 0 :(得分:6)
您具有循环依赖性,因此无法创建这些类。
比方说,您有 A类,它取决于 B类,而这又取决于 A类。然后,要创建 A类,首先应创建 B类,但要创建 B类,首先应创建 A类 em>。因此,根本无法创建 A类和 B类。
当您具有循环依赖性时,这意味着您的设计存在一些问题。您应该尝试重新设计解决方案。
在您的情况下,设计错误非常明显。您有一个SMSSender
,该IPerson
作为发送消息时使用人名的依赖项。但是,请尝试想象一下您将来如何使用此SMS发件人。如果您需要发送带有订单号的信息,该怎么办?将Order
作为参数传递给SMSSender
构造函数?你不应该那样做。
答案是您的SMSSender
对发送的信息一无所知。它应该只是获取一条消息文本并将其发送。因此,您应该从IPerson
中删除SMSSender
的依存关系。
答案 1 :(得分:1)
正如其他几个人在注释中所建议的那样,您创建了一个循环依赖关系-每个类都相互依赖。可以将其视为臭名昭著的“鸡和蛋”场景!您必须先实例化另一个对象才能实例化一个对象。
但是,分离关注点的最简单方法是将IPerson对象传递给Send方法。
您确实 不是 真的要将该人传递到SMSMessageConstructor中,因为那样的话,您就必须为每个创建一个新的SMSMessageConstructor实例。不同的目标人!而是在Send方法中传递IPerson。
此外,我建议将GetName()
方法更改为属性,并建议您将Name和PhoneNumber参数通过 readonly 传递给Person 构造函数不可变性的吸气剂方法。
请参见下面的更新代码:
public interface IPerson
{
string Name { get; }
string PhoneNumber { get; }
}
public interface ISenderMessage
{
void Send(IPerson person, string message);
}
public class Student : IPerson
{
public string Name { get; }
public string PhoneNumber { get; }
public Student(string name, string phoneNumber)
{
Name = name;
PhoneNumber = phoneNumber;
}
}
public class SMSSenderMessage : ISenderMessage
{
public SMSSenderMessage() { }
public void Send(IPerson person, string message)
{
// Access property of person, person.PhoneNumber
// Optionally access name property of person, person.Name
// Send SMS: implement message logic.
}
}
最后,对方法/构造函数使用较新的Expression-bodied成员+ Tuple语法的稍作选择,请参见下文(它稍短且整洁!):
public interface IPerson
{
string Name { get; }
string PhoneNumber { get; }
}
public interface ISenderMessage
{
void Send(IPerson person, string message);
}
public class Student : IPerson
{
public string Name { get; }
public string PhoneNumber { get; }
public Student(string name, string phoneNumber) => (Name, PhoneNumber) = (name, phoneNumber);
public class SMSSenderMessage : ISenderMessage
{
public SMSSenderMessage() { }
public void Send(IPerson person, string message) => // Implement send message logic.
}