2017-02-05 9 views
0

Мне нужно предложение по этому методу программирования интерфейса.Laravel Лучший способ программирования интерфейса

Сценарий: Мне нужно реализовать фиктивный класс 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(); 
} 

Есть ли лучший способ для этого? Любое предложение о моей реализации?

ответ

0

Посмотрите на https://laravel.com/docs/5.3/container#binding-interfaces-to-implementations и https://laravel.com/docs/5.3/container#contextual-binding.

Так что в вашем Provider логике службы, вы можете указать -

$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" 
    } 
} 
+0

привет, я не понимаю различия между моим методом в поставщике услуг и вашим, когда ... нужно ... дать .... мне нужно создать два отдельных контроллера Аватар и фоновый контроллер? – DaveIt

+1

С моей версией вы вводите контракт, а не конкретный класс. Таким образом, вы переводите ответственность с контроллера на то, какую реализацию выполняет контроллер. Однако ваша реализация отличается от того, что вы по существу делаете, создавая псевдоним для 'new ImageUploader (new AvatarImage())' и просто называя его 'AvatarUploader'. Вы создаете ярлык, а не разделяете проблемы. Мне кажется, что ваша версия может добавить сложность с небольшим преимуществом, так как вы можете просто ввести конкретный класс без поставщика услуг. – Gravy

+0

Я понимаю;) thx Gavy, но теперь я должен создать 2 контроллера Avatar и Background, не так ли? – DaveIt