Полиморфные / подключаемые классы PHP - PullRequest
7 голосов
/ 31 января 2010

У меня есть вопрос, который больше похож на вопрос дизайна. У меня есть класс, который определяет кучу функций. Однако я хочу, чтобы поведение некоторых функций изменялось во время выполнения или, по крайней мере, работало как интерфейс плагина во время разработки. например:

class MyClass {  
  public function doSomething();
}

$obj = new MyClass();
// PSEUDO CODE
$obj->doSomething = doSomethingElse;
$obj->doSomething(); // does something else

У меня были разные идеи, как реализовать что-то подобное в «реальном» коде. Однако я не совсем уверен, что это правильный путь. Сначала я подумал, что могу использовать интерфейс для этой цели.

interface IDoSomethingInterface {  
  public function doSomething();
}

class DoSomethingClass implements IDoSomethingInterface
{
  public function doSomething()
  {
    // I do something!
  }
}

class DoSomethingElseClass implements IDoSomethingInterface
{
  public function doSomething()
  {
    // I actually do something else!
  }
}

class MyClass {
  public doSomething(IDoSomething $doSomethingProvider)
  {
    $doSomethingProvider->doSomething();
  }
}

$obj = new MyClass();
$doSomethingProvider = new DoSomethingClass();
$doSomethingElseProvider = new DoSomethingElseClass();

$obj->doSomething($doSomethingProvider); // I do something!
$obj->doSomething($doSomethingElseProvider); // I do something else!

Этот подход можно расширить, чтобы не передавать провайдеру doSomething в качестве параметра, а задавать его либо как член объекта, либо даже как член класса. Однако мне не понравилось, что мне нужно создать экземпляр класса n, который даже не содержит единственной переменной-члена, и единственным методом может быть функция статического класса. Там просто нет необходимости в объекте в этой точке Imo. Затем я собирался использовать функциональные переменные, но тогда я выпал из ООП, что мне тоже не понравилось. Мои вопросы: какой лучший способ реализовать систему, как я описал? Какой подход вы бы попробовали или использовали? Есть ли что-то очевидное, о чем я мог бы и не подумать? Или я должен просто придерживаться подхода интерфейса, и мое плохое предчувствие насчет создания объектов «без тела» - просто бесценное занятие ?! Мне интересно ваши ответы!

Edit:

Поскольку мне действительно интересно выяснить, является ли это (или должно быть) государством или моделью стратегии, я более подробно расскажу о реализации. У меня есть базовый класс коллекций, из которых я получаю различные конкретные реализации. Я хочу иметь возможность выбрать один элемент из любой конкретной реализации - однако я хочу иметь возможность динамически изменять способ выбора этого элемента из коллекции, например:

class MyCollection implements Countable, ArrayAcces, Iterator
{
  // Collection Implementation   
  public function select(ISelectionStrategy $strategy)
  {
    return $strategy->select($this);
  }   
} 

interface ISelectionStrategy
{
  public function select(MyCollection $collection);
}  

class AlphaSelectionStrategy implements ISelectionStrategy
{
  public function select(MyCollection $collection);
  {
    reset($collection);
    if (current($collection))
      return current($collection);
    else
      return null;
  }
}

class OmegaSelectionStrategy implements ISelectionStrategy
{
  public function select(MyCollection $collection)
  {
    end($collection);
    if (current($collection))
      return current($collection)
    else
      return null;
  }
}

class RandomSelectionStrategy implements ISelectionStrategy
{
  public function select(MyCollection $collection)
  {
    if (!count($collection))
      return null;
    $rand = rand(0, count($collection)-1);
    reset($collection);
    while($rand-- > 0)
    {
      next($collection);
    }
    return current($collection);
  }
}

$collection = new MyCollection();
$randomStrategy = new RandomSelectionStrategy();
$alphaStrategy = new AlphaSelectionStrategy();
$omegaStrategy = new OmegaSelectionStrategy();

$collection->select($alphaStrategy); // return first element, or null if none
$collection->select($omegaStrategy); // return last element, or null if none
$collection->select($randomStrategy); // return random element, or null if none 

Это в основном то, чего я хочу достичь. Является ли это сейчас реализацией шаблона стратегии или шаблона состояния - хотя я использовал термин стратегия, потому что в любом случае он больше подходит. Насколько я понимаю, стратегия и структура государства в основном одинаковы, за исключением того, что их намерения различны. Ссылка, предоставленная Гордоном, гласит, что намерение шаблона состояния - «Разрешить объекту изменять свое поведение при изменении его внутреннего состояния», но здесь это не так. Я хочу сказать, чтобы мой класс MyCollection мог «использовать тот или иной алгоритм, чтобы дать мне элемент», а не «дать мне элемент, используя алгоритм, который вы определяете через свое собственное состояние». Надеюсь, что кто-то может прояснить это!

С уважением, Daniel

Ответы [ 2 ]

4 голосов
/ 31 января 2010

Ваш подход правильный. Это шаблон стратегии ( диаграмма UML ):

Проверьте мой ответ на этот вопрос (перейдите туда, где написано Поскольку вы хотите динамически изменить поведение ):

Альтернативой вашему конкретному UseCase было бы объединение стратегий выбора в один класс Service вместо назначения их вашему классу Collection. Затем вместо передачи стратегий в коллекцию передайте коллекцию в класс обслуживания, например

class CollectionService implements ICollectionSelectionService
{
    public static function select(MyCollection $collection, $strategy) {
        if(class_exists($strategy)) {
            $strategy = new $strategy;
            return $strategy->select($collection);
        } else { 
            throw new InvalidArgumentException("Strategy does not exist");
        }    
    }
}
$element = CollectionService::select($myCollection, 'Alpha');

Я оставляю на ваше усмотрение, использовать это со статическими методами или нет. Чтобы предотвратить множественное создание стратегий выбора, вы можете хранить объекты выбора внутри службы для повторного использования.

Для других поведенческих моделей проверьте

3 голосов
/ 31 января 2010

Решение, которое вы обрисовали, более или менее верно. Вы можете этого не знать, но на самом деле это «Государственный» шаблон проектирования . Состояние системы представлено объектом. Если вам нужно изменить состояние, просто замените объект другим состоянием.

alt text

Я бы порекомендовал оставаться с тем, что у вас есть, поскольку это доказано GoF как жизнеспособное решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...