Состояние на основе наследования? - PullRequest
1 голос
/ 20 сентября 2010

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

$choice = 2;
switch($choice) {
     case 1: 
         class child extends parent1
         break;
     case 2: 
         class child extends parent2
         break;
     default:
         class child 
         //extend nothing
         break;
    }

Я думаю, вы можете понять, чего я пытаюсь достичь здесь.

родительские классы

class car { }

Дочерние классы

class ferari extends car { }
class ford extends car { }

классы внуков

class automaticcar { }
class manualcar { }

Теперь этим внукам необходимо указывать родителя в соответствии со значением, отправленным из формы с помощью post.Примерно так

$brand = $_POST['brand'];

if(isset($brand) && !empty($brand)) {
  class automaticcar extends $brand 
}
else {
  class automaticcar extends car  //or even nothing
}

//And then I wish to write the remaining portion of the clas с

Ответы [ 5 ]

5 голосов
/ 20 сентября 2010

Вид наследования, который вы пытаетесь получить, недостижим при использовании языка, наследование которого основано на классах.

Более близкое решение, которое вы можете получить, это использовать своего рода шаблон декоратора с небольшим количеством волшебных методов. как то так:

$choice = 2;
switch($choice) {
     case 1: 
         $obj = new child(new parent1());
         break;
     case 2: 
         $obj = new child(new  parent2());
         break;
     default:
         //extend nothing
         $obj = new child();
         break;
    }

с ребенком, похожим на это:

class child {
    function __construct($composeObj) {
        $this->core = $composeObj;
        // wathever you need to iniyialize
    }
    function __call($name, $params) {
        return call_user_func(array($sthis->core, $name), $parameters);
    }
    // other functions
} // eo child

В этом решении есть некоторые предостережения, но если вы можете справиться с ними (объект не принадлежит семейству составного объекта, call_user_func не передает параметры по ссылке), это подходящее решение.

Лучшим решением является заводской подход, предложенный sandeepan, но вы уже отказались от него.

1 голос
/ 20 сентября 2010

Ferrari ничем не отличается от Ford по свойствам и способам, которые он поставляет. Они оба все еще автомобили. Они просто имеют разные значения для своих атрибутов. Создание специального подкласса не должно быть необходимым для этого. Вместо этого попробуйте этот маршрут:

class Car
{
    protected $_manufacturer;
    protected $_engine;
    protected $_gear;
    protected $_price;
    protected $_color;

    public function __construct($manufacturer, $engine, $gear, $price, $color)
    {
        // setting properties
    }
}

class CarFactory
{
    public static function createFerrari()
    {
        $engine = new Engine(500); // PS
        $gear = new Gear(6, 'manual');
        return new Car('Ferrari', $engine, $gear, '250000', 'red');
    }

    public static function createFord()
    {
        $engine = new Engine(90); // PS
        $gear = new Gear(5, 'automatic');
        return new Car('Ford', $engine, $gear, '50000', 'black');
    }

    // other car creation methods ...
}

Если вы расширяете класс, вы создаете отношение is-a . Подкласс является специализированным родительским классом. Механизм и Двигатель - это не что-то, что Автомобиль есть , но что-то, что автомобиль имеет . Всякий раз, когда вы можете описать класс, чтобы у было что-то , это кандидат для его собственного класса или просто для атрибута. Должен ли это быть его собственный класс, зависит от того, инкапсулировал ли он свое уникальное состояние и ответственность.

0 голосов
/ 13 июня 2016

Я знаю, что опаздываю почти на шесть лет.Но на всякий случай, если кто-то приземлится здесь снова, я решил поместить это здесь.

Обратите внимание, что я не предполагаю, что подразумеваемое понимание того, что имена классов Car, Ferrari, Ford и т. Д. Являются транспортными,Чтобы можно было применять этот шаблон в общем виде.

Я буду использовать любой из следующих подходов в порядке убывания предпочтений:

  • Псевдоним класса Руководство по PHP (PHP 5 >= 5.3.0, PHP 7)

    // Assuming $my_brand is the required brand 
    if (!class_exists($my_brand))
    {
        // Raise suitable warning here and exit
        exit('Brand ' . $my_brand . 'not found.');
    }
    
    class_alias($my_brand, 'MyBrand');
    
    class AutomaticCar extends MyBrand
    {
    }
    
  • Условное накопление наследования (Слишком много работы, но полезно впроект большего размера)

    // File: lib/MyBrand/Ferrari.php
    class MyBrand extends Ferrari
    {
    }
    

    // File: lib/MyBrand/Ford.php
    class MyBrand extends Ford
    {
    }
    

    // Then in your main code, assuming $my_brand is the required brand 
    if (!file_exists('lib/MyBrand/' . $my_brand . '.php'))
    {
        // Raise suitable warning here and exit
        exit('Brand ' . $my_brand . 'not found.');
    }
    
    class AutomaticCar extends MyBrand
    {
    }
    

Другие шаблоны, которые я могу прямо сейчас (например, Factory Design и Decorator Pattern) Подумайте о том, чтобы выбрать другие маршруты, которые не соответствуют конкретной теме.Вот и все пока.

0 голосов
/ 20 сентября 2010

Во-первых, я действительно не думаю, что вы достаточно хорошо понимаете объектно-ориентированные принципы, чтобы запрашивать эту функциональность.Это действительно не нужно со стилем ООП, который реализует PHP.

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

<?php
    class Mixin
    {
        private $objects = array();
        private $funcs = array();

        public function addMixin(Mixable $object)
        {
            $exported_vars = $object->exportVars();
            foreach ($exported_vars as $key => &$ref)
                $this->$key = &$ref;

            $vars = array();
            foreach (array_keys(get_object_vars($this)) as $key)
                $vars[$key] = &$this->$key;
            $object->importVars($vars);

            $this->objects[] = $object;
        }

        public function __call($method, $args)
        {
            if (!isset($this->funcs[$method]))
            {
                $found = false;
                foreach ($this->objects as $obj)
                {
                    if (method_exists($obj, $method))
                    {
                        $found = true;
                        $this->funcs[$method] = array($obj, $method);
                        break;
                    }
                }

                if (!$found)
                    throw new Exception("method doesn't exist");
            }

            return call_user_func_array($this->funcs[$method], $args);
        }
    }

    class Mixable
    {
        public function exportVars()
        {
            $vars = array();

            foreach (array_keys(get_object_vars($this)) as $key)
            {
                $vars[$key] = &$this->$key;
            }

            return $vars;
        }

        public function importVars($vars)
        {
            foreach ($vars as $key => &$ref)
            {
                $this->$key = &$ref;
            }
        }
    }
?>

Вы бы использовали это как:

<?php    
    class Parent1 extends Mixable
    {
        protected $name = 'Parent 1';

        public function p1()
        {
            print "P1\n";
        }
    }

    class Parent2 extends Mixable
    {
        protected $name = 'Parent 2';

        public function p2()
        {
            print "P2\n";
        }
    }

    class Child1 extends Mixin
    {
        public function whoAmI()
        {
            print $this->name."\n";
        }
    }

    $foo = new Child1();
    if (mt_rand(1, 2) == 1)
    {
        $foo->addMixin(new Parent1());
        $foo->p1();
    }
    else
    {
        $foo->addMixin(new Parent2());
        $foo->p2();
    }

    $foo->whoAmI();
?>

Пожалуйста, не пытайтесь использовать код!Даже если бы он был готов к производству, это ужасная концепция.Я поставил его здесь, чтобы показать вам, как это будет работать.

Я думаю, что вы действительно должны делать что-то более похожее на шаблон Factory: создайте класс CarFactory, который возвращает правильнов подклассе Car.(Или вы можете создать фабричный метод в классе Car.)

Это может быть что-то вроде Car::get($_POST['brand']).

0 голосов
/ 20 сентября 2010

Является ли ваш вопрос "наследование на основе условий хорошо?"Тогда да, это выглядит необходимым во многих случаях.Но я думаю, что было бы лучше инициировать объекты условно, а не определять расширенные классы внутри условия.

Обновления
Насколько я понимаю, вы хотите иметь различные атрибуты / функции дочернего класса в зависимости от условия.Я столкнулся с аналогичной потребностью / проблемой в моем проекте.Там это было связано с логикой зрения.Вы можете проверить Как мой подход к повторному использованию логики представления в моем проекте?

Если я правильно понимаю вашу проблему, то вы должны заранее подготовить дочерние классы, как показано ниже, в отдельных файлах php:-

класс child1

class1 child extends parent1

класс child2

class2 child extends parent2

И в части условия выполните что-то вроде:-

$choice = 2;
switch($choice) {
     case 1: 
         include /path/to/child1;
         $obj = new child1();
         break;
     case 2: 
         include /path/to/child2;
         $obj = new child2();
         break;
     default:
         include /path/to/child;
         $obj = new child();
         //extend nothing
         break;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...