【问题标题】:Laravel Best way to programming an interfaceLaravel 编程接口的最佳方法
【发布时间】:2017-06-22 14:46:52
【问题描述】:

我需要一个关于这种编程接口的方法的建议。

场景: 我需要实现一个虚拟类ImageUploader 然后在构造函数上接收一个接口并将图像保存在我的目录中。这是为了学习目的,所以如果我做得对,我需要你的建议:

这是我在 Laravel 5.3 框架上的实现:

1:实现的虚拟接口,因此我可以创建不同的方式来存储我的图像

//dummy interface

namespace App\Lib\ImageUploader\Drivers;

interface ImageInterface
{
   public function hello();
}

2:这里有两个实现我的接口的驱动程序。每个都作为自己的方法hello(在现实生活中,例如每个类可能有自己的任何驱动程序的保存方法)

// Avatar Driver Class

namespace App\Lib\ImageUploader\Drivers;

class AvatarImage implements ImageInterface
{
     public function hello()
     {
          return 'I am a AvatarImage';
     }
}

另外一个类,例如BackgroundImage可以保存用户上传图片的桌面版和手机版:

// Background Driver Class


namespace App\Lib\ImageUploader\Drivers;

class BackgroundImage implements ImageInterface
{
   public function hello()
   {
     // this is a dummy method, in real life this class will save 2 images (desktop + mobile)
     return 'I am a BackgroundImage';
   }

}

这是我的 ImageUploader 具有“编程到接口”策略的类:

// ImageUploader.php
// this class will implement all methods that I need for manage saving operations

namespace App\Lib\ImageUploader;
use App\Lib\ImageUploader\Drivers\ImageInterface;


class ImageUploader
{

   protected $driver;

   public function __construct(ImageInterface $driver)
   {
      $this->driver = $driver;
   }

   public function save()
   {
      return  $this->driver->hello();
   }
}

现在我创建自己的 Laravel 框架服务提供者:

namespace App\Providers;

use App\Lib\ImageUploader\Drivers\AvatarImage;
use App\Lib\ImageUploader\Drivers\BackgroundImage;
use App\Lib\ImageUploader\ImageUploader;
use Illuminate\Support\ServiceProvider;

class ImageUploadServiceProvider extends ServiceProvider
{
    /**
    * Bootstrap the application services.
    *
    * @return void
    */
    public function boot()
   {
     //
   }

    /**
    * Register the application services.
    *
    * @return void
    */

    public function register()
    {
       $this->registerAvatar();
       $this->registerBackground();
    }

    protected function registerAvatar(){
       $this->app->bind('AvatarUploader', function () {
          return new ImageUploader(new AvatarImage());
       });
    }

    protected function registerBackground(){
       $this->app->bind('BackgroundUploader', function () {
         return new ImageUploader(new BackgroundImage());
       });
    }
}

最后,我尝试在控制器中使用我的类,例如当用户尝试上传您的头像图片或新的背景图片时:

// this will produce "I am a AvatarImage" in real life this line create thumbnail and will save my image in my local directory

public function store(Request $request){
    (App::make('AvatarUploader'))->save();   
}

有没有更好的方法呢?对我的实现有什么建议吗?

【问题讨论】:

    标签: php laravel interface laravel-5.3


    【解决方案1】:

    看看https://laravel.com/docs/5.3/container#binding-interfaces-to-implementationshttps://laravel.com/docs/5.3/container#contextual-binding

    所以在你的服务提供者逻辑中,你可以指定 -

    $this->app->when(AvatarController::class)
              ->needs(ImageInterface::class)
              ->give(function () {
                  return new AvatarUploader();
              });
    
    $this->app->when(BackgroundController::class)
              ->needs(ImageInterface::class)
              ->give(function () {
                  return new BackgroundImage();
              });
    

    然后在您的控制器或其他类中,只需依赖注入 ImageInterface 接口而不是具体类。

    class AvatarController extends Controller
    {
        protected $imageInterface;
        public function __construct(ImageInterface $imageInterface)
        {
            $this->imageInterface = $imageInterface;
        }
    
        public function store()
        {
            return $this->imageInterface->hello(); // returns "I am an Avatar Image"
        }
    }
    
    class BackgroundController extends Controller
    {
        protected $imageInterface;
        public function __construct(ImageInterface $imageInterface)
        {
            $this->imageInterface = $imageInterface;
        }
    
        public function store()
        {
            return $this->imageInterface->hello(); // returns "I am a Background Image"
        }
    }
    

    【讨论】:

    • 嗨,我不明白我在服务提供商中的方法和你的方法之间的区别是什么时候...需要...给...。我需要创建两个单独的控制器头像和后台控制器?
    • 在我的版本中,你注入的是契约而不是具体的类。这样,您就可以将关于控制器运行哪个实现的责任移出控制器。然而,您的实现是不同的,因为您本质上所做的是为new ImageUploader(new AvatarImage()) 创建一个别名并简单地调用它AvatarUploader。您正在创建一条捷径 - 而不是分离关注点。在我看来,您的版本可能会增加复杂性而没有什么好处,因为您也可以在没有服务提供者的情况下注入具体类。
    • 我明白 ;) thx Gavy 但现在我必须创建 2 个控制器 Avatar 和 Background,不是吗?
    • 好的,我已经创建了我的两个控制器,AvatarController 和BackgroundController,但是我需要在我的UsersController(默认的laravel 用户控制器)中使用如何实现?我需要通过方法将它传递给 UsersController?
    猜你喜欢
    • 2011-02-07
    • 2019-08-24
    • 1970-01-01
    • 2011-09-24
    • 2012-12-28
    • 1970-01-01
    • 2022-08-02
    • 2020-05-27
    • 1970-01-01
    相关资源
    最近更新 更多