鉴于以下关于依赖倒置的复数的例子,我对这是如何工作非常困惑。所以我们给出了以下接口和派生类实现。
public interface INotifyCustomer
{
void NotifyCustomer(Cart cart);
}
public class NotifyCustomerService : INotifyCustomer
{
public void NotifyCustomer(Cart cart)
{
string customerEmail = cart.CustomerEmail;
if (!String.IsNullOrEmpty(customerEmail))
{
using (var message = new MailMessage("orders@somewhere.com", customerEmail))
using (var client = new SmtpClient("localhost"))
{
message.Subject = "Your order placed on " + DateTime.Now;
message.Body = "Your order details: \n " + cart;
try
{
client.Send(message);
}
catch (Exception ex)
{
Logger.Error("Problem sending notification email", ex);
throw;
}
}
}
}
}
我无法理解的部分是这样的想法:简单地调用如下所示的接口以某种方式调用派生类而不实例化甚至提及派生类。示例如下:
public class Order
{
private readonly Cart cart;
private readonly PaymentDetails paymentDetails;
private readonly INotifyCustomer notifyCustomer;
public Order(Cart cart, PaymentDetails paymentDetails, INotifyCustomer notifyCustomer)
{
this.cart = cart;
this.paymentDetails = paymentDetails;
this.notifyCustomer = notifyCustomer;
}
public void Checkout(Cart cart, PaymentDetails paymentDetails, bool notify)
{
if (paymentDetails.PaymentMethod == PaymentMethod.CreditCard)
{
ChargeCard(paymentDetails, cart);
}
ReserveInventory(cart);
if (notify)
{
notifyCustomer.NotifyCustomer(cart);
}
}
}
任何人都可以帮我解释一下吗?我并不是C#的新手,但是并没有使用太长时间,我在过去几年里更像是一个java人,我知道C#和Java之间存在根本区别。但我看不出这是如何或为何有效?
答案 0 :(得分:3)
即使这个问题确实没有明确的“答案”(可能过于广泛的SO范围),我仍然希望发布一个答案,希望有助于巩固依赖注入的理念。
考虑一下:
从现在开始,您编写的每一段代码都只会引用对象的摘要。摘要意味着接口(或可能是抽象类或基类,但现在我的观点之外)。
这样做的好处是你的代码不关心抽象是如何实现的,它所知道或关心的是它所期望的那些方法或属性。
这为您带来了各种好处:
我认为让你困惑的部分是你所认为的依赖注入的“魔力”。构造函数的参数类型为INotifyCustomer
。当你的Order
类被实例化时,那些参数有被提供(是的,我知道可以在技术上传递null)。既然我们已经确定你的代码绝对无关紧要传入的内容,只要它的类型为INotifyCustomer
,你的代码就会像直接传入具体内容一样运行(但是现在我们所有依赖注入的好处。)
答案 1 :(得分:1)
您的界面实施是合同。它简单地说,“如果你实现我(接口),那么你必须提供这个方法NotifyCustomer
,它接受一个Cart
并且不返回一个值(即void
)。如果您实施它,只要您执行上述操作,就可以在NotifyCustomer
方法中执行任何操作。
您的班级Order
不知道notifyCustomer
是什么,只是它实现了INotifyCustomer
。但是,您的编译器知道,因此当代码编译并运行时,它实际上会在NotifyCustomerService
中调用您的代码。通过利用依赖注入,您可以设计代码而无需关心或知道依赖关系是如何实现的,只要它们满足合同即可。
答案 2 :(得分:1)
实际上,类Order
中的任何内容都没有实例化NotifyCustomerService
,但它知道INotifyCustomer
类型的对象具有NotifyCustomer方法,该方法具有指定的参数和返回类型。它不必知道如何在类NotifyCustomerService
中实现该方法。