Why Dependency Injection
A constructor that calls `new SmtpEmailSender()` has quietly chosen, for every caller and every test, the one and only way this class will ever send mail. Delete that single line and the class stops deciding.
- ▸Done by hand, the pattern is just
new OrderService(new SmtpEmailSender()); a container only writes that line for you. - ▸Move one
newout of one constructor and the class becomes testable, swappable, and reconfigurable. - ▸Only one thing inverts: which concrete type to use leaves the class for whoever builds it.
An OrderService needs to send a confirmation, so its constructor does the obvious thing: it builds the sender it needs.
public class OrderService { private readonly SmtpEmailSender _sender; public OrderService() { _sender = new SmtpEmailSender(); // built right here } public void Place(Order order) => _sender.Send(order.Receipt()); }
That collaborator is a dependency: OrderService needs an SmtpEmailSender to do its job. Building it inside the constructor reads as harmless, but it welds the two together. OrderService now mentions SmtpEmailSender by name, so it can only ever send mail one way. Want to point a test at an in-memory sender instead? You cannot, the class hard-codes the real one. Want a second OrderService that logs instead of mails? You edit OrderService itself. The new SmtpEmailSender() call is the weld, and everything stiff about this class traces back to it.