Let's consider another example to solidify our understanding. Perhaps we want to notify customers of charges to their account. We'll define two interfaces, or contracts. These contracts will gie us the flexibility to change out their implementations later.
让我们考虑另一个例子来巩固理解。 可能我们想要去提醒用户该交钱了。 我们会定义两个接口, 或者约定。这些约定使我们在更改实际实现时更加灵活。
interface BillerInterface {
public function bill(array $user, $amount);
}
interface BillingNotifierInterface {
public function notify(array $user, $amount);
}
Next we'll build an implementation of our BillerInterface
contract:
接下来我们要写一个BillerInterface
的实现:
class StripeBiller implements BillerInterface{
public function __construct(BillingNotifierInterface $notifier)
{
$this->notifier = $notifier;
}
public function bill(array $user, $amount)
{
// Bill the user via Stripe...
$this->notifier->notify($user, $amount);
}
By separating the responsibilities of each class, we're now able to easily inject various notifier implementations into our billing class. For example, we could inject a SmsNotifier
or an EmailNotifier
. Our biller is no longer concerned with the implementation of notifyingg, but only the contract. As long as a class abides by its contract (interface), the biller will gladly accept it. Furthermore, not only do we get added flexibility, we can now test our biller in isolation from our notifiers by injecting a mock BillingNotifierInterface
.
只要遵守了每个类的责任划分,我们很容易将不同的提示器(notifier)注入到账单类里面。 比如,我们可以注入一个SmsNotifier
或者EmailNotifier
。账单类只要遵守了约定,就不用再考虑如何实现提示功能。只要是遵守约定(接口)的类, 账单类都能用。这不仅仅是方便了我们的开发,而且我们还可以通过模拟BillingNotifierInterface
来进行无痛测试。
Be The Interface 使用接口
While writing interfaces might seem to a lot of extra work, they can actually make your development more rapid. Use interfaces to mock and test the entire back-end of your application before writing a single line of implementation!
写接口可能看上去挺麻烦,但实际上能加速你的开发。你不用实现任何接口,就能使用模拟库来模拟你的接口,进而测试整个后台逻辑!
So, how do we do dependency injection? It's simple:
那我们如何做依赖注入呢?很简单:
$biller = new StripeBiller(new SmsNotifier);
That's dependency injection. Instead of the biller being concerned with notifying users, we simply pass it a notifier. A change this simple can do amazing things for your applications. Your code immediately becomes more maintainable since class responsibilities are clearly delineated. Also, testability will skyrocket as you can easily inject mock dependencies to isolate the code under test.
这就是依赖注入。 biller不需再考虑提醒用户的事儿,我们直接传给他一个提示器(notifier)。 这种微小的改动能使你的应用焕然一新。 你的代码马上就变得更容易维护, 因为明确指定了类的职责边界。 并且更容易测试, 你只需使用模拟依赖即可。
But what about IoC containers? Aren't they necessary to do dependency injection? Absolutely not! As we'll see in the following chapters, containers make dependency injection easier to manage, but they are not a requirement. By following the principles in this chapter, you can practice dependency injection in any of your projects, regardless of whether a container is avaliable to you.
那IoC容器呢? 难道依赖注入不需要IoC容器么?当然不需要!在接下来的章节里面你会了解到,容器使得依赖注入更易于管理,但是容器不是依赖注入所必须的。只要遵循本章提出的原则, 你可以在你任何的项目里面实施依赖注入,而不必管该项目是否使用了容器。
A common criticism of use of interfaces in PHP is that it makes your code too much like “Java”. What people mean is that it makes the code very verbose. You must define an interface and an implementation, which leads to a few extra key-strokes.
有人会说使用接口让PHP代码看上去太像Java了——即代码太罗嗦了——你必须定义接口然后实现它,要多按好多下键盘。
For small, simple applications, this criticism is probably valid. Interfaces are often unnecessary in these applications, and it is “OK” to just couple yourself to an implementation you know won't change. There is no need to use interfaces if you are certain your implementation will not change. Architecture astronauts will tell you that you can “never be certain”. But, let's face it, sometimes you are.
对于小而简单的应用来说,以上说法也对。 接口通常是不必要的。将代码耦合到那些你认为不会改变的地方也是可以的。在你确信不会改变的地方就没有必要使用接口了。架构师说“不会改变的地方是不存在的”。不过话说回来,有时候的确不会改。
Interfaces are very helpful in large applications, and the extra key-strokes pale in comparison to the flexibility and testability you will gain. The ability to quickly swap implementations of a contract will “wow” your manager, and allow you to write code that easily adapts to change.
在大型应用中接口是很有帮助的。和提升的代码灵活性、可测试性比起来,多敲键盘费的功夫就微不足道了。当你迅速的切换了代码实现的时候,你的经理一定会被你的神速吓一跳的。你也可以写出更适应变化的代码。
So, in conclusion, keep in mind that this book presents a very “pure” architecture. If you need to scale it back for a small application, don't feel guilty. Remember, we're all trying to “code happy”. If you're not enjoying what you're doing or you are programming out of guilt. step back and re-evaluate.
总而言之, 记住本书提倡“简单”架构。如果你在写小程序的时候无法遵守接口原则, 别觉得不好意思。 要记住我们写代码是要快乐的写。如果你不喜欢写接口,那就先简单的写代码吧。日后再精进即可。