所以我是一名经验丰富的开发人员,即使我已经使用了一段时间了,我也很喜欢魔法如何在表面下发生,它是如何在通过IoC容器实例化类时自动绑定实现的,现在我是试图了解设计模式的基础知识,并了解事情的实际运作方式。
所以我开始使用Animal示例:
abstract class Animal
{
abstract function makeSound();
}
class Dog extends Animal
{
public function makeSound()
{
echo "Bark!\n";
}
}
class Cat extends Animal
{
public function makeSound()
{
echo "Bark!\n";
}
}
所以我正在阅读Head First Design Patterns,我正在努力充分利用这本书。此时每次创建一个新的Animal时,我都必须实现make声音方法,这种方法在大多数情况下会有所不同。
所以这本书告诉我,我应该编写一个Soundable接口,然后在Animal扩展类中实现该接口。
我终于想出了类似的东西:
interface Soundable
{
function sound();
}
class Bark implements Soundable
{
public function sound()
{
return "Bark!\n";
}
}
class Meow implements Soundable
{
public function sound()
{
return "Meow!\n";
}
}
class Animal
{
public $soundable;
public function __construct(Soundable $soundable)
{
$this->soundable = $soundable;
}
public function makeSound()
{
echo $this->soundable->sound();
}
}
class Dog extends Animal
{
}
class Cat extends Animal
{
}
function makeAnimal(Animal $animal){
return $animal;
}
// Making a dog
$animal = makeAnimal(new Dog(new Bark()));
$animal->makeSound();
// Making a cat
$animal = makeAnimal(new Cat(new Meow()));
$animal->makeSound();
所以现在当我有另一种吠叫或喵喵叫的动物时,我可以在制作动物时简单地实例化该实施。
现在我的问题是如何告诉PHP在实例化new Bark()
类时自动传递Dog
,因为它会咆哮,我不想每次实例化一个新的时都写它{ {1}}对象。
那么我如何使用Laravel在实例化Dog时自动传递Bark对象的类似魔法。
PS:我还在学习,所以在理解这些原则的同时,我可能会走错路。如果你知道的话,请指导我。答案 0 :(得分:2)
首先,小记:这本书错了。该界面应称为Audible
或Vocal
。 “合理”不是一个真正的词,作者应该感到尴尬。另外,调用与接口同名的变量有点不好。
另一件事是:Laravel的IoC实际上只是一个美化的服务定位器,所以它在这里不会对你有所帮助。
通常,您有两种选择:
在这种情况下,我倾向于推荐Auryn。但是,如果你愿意通过有限的配置跳出一些额外的箍,你也可以使用Symfony's DIC。
如果您使用的是Auryn,那么您的狗和猫的初始化就是:
$injector = new Auryn\Injector;
$dog = $injector->make('Dog');
$cat = $injector->make('Cat');
库本身会查找Dog
构造函数的反映,并检测它还需要创建一个新的Bark
实例。
答案 1 :(得分:1)
您可以使用工厂方法创建简单的动物工厂(听起来很奇怪)。
通常实施工厂类,因为它们允许项目更紧密地遵循SOLID原则。特别是界面隔离和依赖反转原理。
有关详细信息,请查看https://www.sitepoint.com/understanding-the-factory-method-design-pattern/ 只记得如果你想写下一些单元测试不使用静态方法,只是实例化工厂,将来可能需要创建一些具有依赖性的工厂。
<?php
class AnimalFactory
{
public function createDog() : Dog
{
return new Dog(new Bark());
}
}
$factory = new AnimalFactory();
$dog = $factory->createDog();
答案 2 :(得分:0)
我认为在这里使用IoC将是一个很好的解决方案。
来自Laravel Docs(上下文绑定)
有时您可能有两个使用相同接口的类,但您希望在每个类中注入不同的实现。例如,当我们的系统收到新订单时,我们可能希望通过PubNub而不是Pusher发送事件。 Laravel提供了一个简单,流畅的界面来定义这种行为:
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('App\Contracts\EventPusher')
->give('App\Services\PubNubEventPusher');
因此,laravel中的服务提供商可能看起来像
public function register()
{
$this->app->when(Dog::class)->needs(Soundable::class)->give(Bark::class);
$this->app->when(Cat::class)->needs(Soundable::class)->give(Meow::class);
}
然后你可以使用Laravel的依赖注入包含器来实例化你的类
$dog = app()->make(Dog::class);
$dog->sound(); // Bark!
$cat = app()->make(Cat::class);
$cat->sound(); // Meow!
总结起来,与你的问题有关:
那么我如何使用Laravel用来传递树皮的类似魔法 实例化Dog时自动对象。
答案 3 :(得分:-1)
我不知道laravel,但在我看来你的代码应该是:
interface Soundable
{
function sound();
}
class Animal
{
protected name;
public function __construct($name) {
$this->name=name;
}
public function get_name() { return $this->name; }
}
class Dog extends Animal implements Soundable
{
public function sound()
{
return "Bark!\n";
}
}
class Cat extends Animal implements Soundable
{
public function sound()
{
return "Meow!\n";
}
}
// Making a dog
$animal = new Dog("Fido");
$animal->sound();
// Making a cat
$animal = new Cat("Fuffi");
$animal->sound();
echo $animal->get_name(); // print "Fuffi"
因此,您可以看到,如果您只想实现该接口,则甚至不需要Animal类。实际上,我只是为了实现一些对所有降序类都有用的方法(例如,get_name,它返回受保护的属性“name”),它仍然有用,但它仍然有用。