Реализация шаблонов PHP Abstract Factory

0

Я читаю о различных доступных там шаблонах. В настоящее время я на шаблоне абстрактной фабрики, и я думаю, что у меня довольно хорошее понимание. Мои ресурсы, помимо википедии: http://www.tutorialspoint.com/design_pattern/abstract_factory_pattern.htm http://www.oodesign.com/abstract-factory-pattern.html https://github.com/domnikl/DesignPatternsPHP/дерево/ведущий/Творения /AbstractFactory

Я использую Apple и ее продукты, чтобы создать образец шаблона Abstract Factory в качестве примера. Я понимаю, что дублирование кода - плохой дизайн, поэтому причина, по которой я пишу это. Мой код пока:

abstract class AbstractAppleFactory {
    abstract public function createiPod( $capacity, $type, $color, $engraving );
    abstract public function createiPhone( $capacity, $type, $color, $antenna );
    abstract public function createComputer( $type, $HDCapacity, $CPU, $ram );
}

class iPodFactory extends AbstractAppleFactory {
    public function createiPod( $capacity, $type, $color, $engraving ) {
        $class = 'iPod' . $type;

        return new $class( $capacity, $color, $engraving);
    }

    public function createiPhone( $capacity, $type, $color, $antenna ){ /* no implementation necessary */}
    public function createComputer( $type, $HDCapacity, $CPU, $ram ){ /* no implementation necessary */}
}

interface iPlayer {
    public function play();
    public function stop();
    public function fastForward();
    public function rewind();
}

abstract class iPod implements iPlayer {
    protected $capacity;
    protected $color;
    protected $engraving;

    public function __construct( $capacity, $color, $engraving = null ) {
        $this->capacity = $capacity;
        $this->color = $color;
        $this->engraving = $engraving;
    }
}

class iPodClassic extends iPod {
    public function play() {/* implementation goes here */}
    public function stop() {/* implementation goes here */}
    public function fastForward() {/* implementation goes here */}
    public function rewind() {/* implementation goes here */}
}
class iPodShuffle extends iPod {
    public function play() {/* implementation goes here */}
    public function stop() {/* implementation goes here */}
    public function fastForward() {/* implementation goes here */}
    public function rewind() {/* implementation goes here */}
}

и т.д. и т.д. Здесь слишком много кода. Я знаю, что лучше организовать в каталогах и пространствах имен. Это не то, что я изучаю прямо сейчас. Я узнаю о моделях и концепциях ООП.

Этот раздел посвящен:

class iPodFactory extends AbstractAppleFactory {
    public function createiPod( $capacity, $type, $color, $engraving ) {
        $class = 'iPod' . $type;

        return new $class( $capacity, $color, $engraving);
    }

    public function createiPhone( $capacity, $type, $color, $antenna ){ /* no implementation necessary */}
    public function createComputer( $type, $HDCapacity, $CPU, $ram ){ /* no implementation necessary */}
}

Из-за наследования/абстракции я вынужден реализовать два ненужных метода на несвязанной фабрике. createiPhone() и createComputer(). Правильно ли я делаю шаблон абстрактной фабрики? Опять же, "дублирование кода - плохой дизайн!" Какой лучший способ сделать это?

  • 0
    Вы должны придерживаться одного шаблона по всему проекту? Я лично использую шаблоны проектирования по мере необходимости. Рассматривали ли вы использование внедрения зависимостей для внедрения вашего объекта iPhone в любой класс, чтобы вы могли использовать его методы?
  • 0
    Это просто упражнение.
Теги:
oop
design-patterns
abstract-factory

2 ответа

3
Лучший ответ

Думаю, вы совершили большую ошибку. Абстрактная фабричная цель - создать абстракцию для создания семейства продуктов, поэтому вы можете легко изменить ее на другую семью. fe Apple => Samsung :)

interface ComputerAbstractFactory {
    /**
    * @return Tablet
    */
    function createTablet();
    /**
    * @return Phone
    */
    function createPhone();
    /**
    * @return Computer
    */
    function createComputer();
}

class AppleComputerFactory implements ComputerAbstractFactory {}

class SamsungComputerFactory implements ComputerAbstractFactory {}

class IPad implements Tablet {}

class GalaxyTab implements Tablet {}

...

Использование абстрактного шаблона фабрики имеет смысл, когда вы хотите переключаться между обеими компаниями. Ваш код должен зависеть только от абстракций (принципы SOLID) ComputerAbstractFactory, Tablet, Phone, Computer. Таким образом, если вы решите (например, каким-то переключателем конфигурации), какой производитель следует использовать, достаточно, чтобы вы ввели выбранную вами реализацию ComputerAbstractFactory в свой бизнес-код, и все готово - все работает, создаются планшеты, телефоны и т.д.

Вам нужно решить, какую абстракцию вы хотите создать в своем приложении, чтобы вызывающий код не был связан с конкретными реализациями этой абстракции. Я считаю, что IPlayer - это то, что вы хотите, где IPodClassic IPodShuffle - это конкретные реализации. Если я прав, вам следует создать IPlayerFactory

class IPlayerFactory {
    /**
    * @return IPlayer
    */
    function create() {...}
}

О дублировании, о котором вы говорили. Если iPodFactory расширяет AbstractAppleFactory, он должен реализовать весь его метод (btw, если AbstractAppleFactory не имеет какой-либо реализации, он должен быть интерфейсом). Вы нарушили принцип Лискова из принципов SOLID. Краткая версия - если вызывающий код зависит от AbstractAppleFactory, и он получает IPodFactory в качестве конкретной реализации для работы, он будет ломаться при вызове createiPhone или createComputer - поэтому абстракция не работает в этом случае.

  • 0
    Спасибо @Jakub! Это первый раз, когда я сделал упражнение на паттерне.
  • 0
    Я просмотрел определение abstraction и вы на 100% правы. Я думаю, я никогда не знал, что это было!
0

Вы на правильном пути, но я думаю, что интерфейс неправильный.

Прежде всего, не используйте abstract класс, если вам не нужен метод, который будет использоваться для дочерних классов. Использовать interface будет лучше.

Это было бы моим решением:

<?php
interface AppleFactoryInterface
{
    function create($data);
}

И вот iPhoneFactory:

<?php
class iPhoneFactory implements AppleFactoryInterface
{
    public function create($data)
    {
        $klass = sprintf('iPhone'.$data['type']);
        $instance = new $klass;
        $instance->setFromArray($data);

        return $instance;
    }
}

Как вы можете видеть, у меня меньше кода, который лучше понять.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню