Наследования, интерфейсы и абстрактные классы.

Активист

Активист
Команда форума
В общем, есть три листинга, какой будет правильнее использовать в контексте поставленной задачи

Листиг 1
PHP:
<?php
interface client {
	public function add();
} 

class client_base {
	protected function save() {
		// some code here
	}
}

class client_persone extends client_base implements client {
	public function add() {
		// some code here
		$this->save();
	}
}

class client_company extends client_base implements client {
	public function add() {
		// some code here
		$this->save();
	}
}
?>

Листиг 2
PHP:
<?php
abstract class client_base {
	/**
	 * В абстрактном классе мы можем декларировать это
	 * @var bar
	 */
	protected $foo;
	
	/**
	 * phpDOC hear
	 */
	protected function save() {
		// some code here
	}

	/**
	 * В отличии от interface, в абстактом классе мы можем декларировать protected
	 */
	abstract protected function del();
}

class client_persone extends client_base {
	public function add() {
		// some code here
		$this->save();
	}
	
	protected function del() {
		// some code here
	}
}

class client_company extends client_base {
	public function add() {
		// some code here
		$this->save();
	}
	protected function del() {
		// some code here
	}
}
?>

Листиг 3
PHP:
<?php
interface client {
	public function add();
} 

class client_persone implements client {
	public function add() {
		// some code here
		$this->save();
	}	
	protected function save() {
		// some code here
	}
}

class client_company extends client_persone implements client {
	public function add() {
		// some code here
		$this->save();
	}
}
?>
 
в контексте поставленной задачи
Где задача-то?

PS: here, person

PPS: если пытаться гадать, то самой удачной реализацией лично мне выглядит вариант 3, только

PHP:
class client_company extends client_persone

без implements
 
Вопрос в том, что когда был один "тип клиента" - клиент(физ, юр) в одном лице, потом появился еще один тип клиента "юр", который координатно стал отличаться от обычного типа (физ), собственно - есть решение использовать наследование, но его можно реализовать по-разному, и вот те листинги эту реализацию делают.

zerkms
А чем интерфейс (implements) плох?

В 3-ем листинге вроде код проще, и т.п, но видно, что код допилен после, кроме того, для создания новых типов клиента нет никаких инструкций для программиста (абстраных классов и т.п.).

Или я чего не догоняю в реализации. Сам выбрал вариант 1, но вскрылась проблема, я не могу никуда декларировать некий абстрактный метод (прототип метода) уровня доступа protected (интерфейс как бы для public только), а множественного наследования нет. Этим я хочу заставить самого себя в будущем знать, что из base выпилен метод, и его нужно обязательно описывать дети, но указать это не могу.
 
Активист
Тем, что ты уже реализовал его, в иерархии на 1 уровень выше.
 
Мне нравица реализация с абстрактным классом, в него можно вынести общие вещи для всех наследников.

А в третьем варианте
PHP:
class client_company extends client_persone implements client

зачем тут имплементс, если он реализован у client_persone?

и person)
 
melo
Если наследники действительно принадлежат одной иерархии наследования (т.е. наследование применено правильно и к месту), и базовый класс так и так включает все эти методы (которые в наследниках лишь будут уточнены) - тогда смысла выделять абстрактный класс совершенно нет.
 
я тоже за второй вариант,

третий вариант как бы говорит "клиент компания является клиентом человеком", что в реальности не совсем так
 
Ничто не мешает сделать так:
PHP:
interface client {
    public function add();
} 

abstract class client_base  implements client  {
    protected function save() {
        // some code here
    }
}
//и т.д.
Интерфейсы и абстрактные классы решают немного разные задачи, и вполне могут использоваться совместно, если такая задача возникла.
 
А вот объясните, зачем для описания интерфейса одной сущности плодить и интерфейс, и абстрактный класс.

В моём понимании нужно использовать или/или. Нужна общая реализация методов - абстрактный класс, не нужна или это описание поведения (enumerable, countable, playable и т.д.) - интерфейс, а вот и интерфейс client + класс client_base - не понимаю.
 
Интерфейс содержит описание публичных методов, необходимых для написания своих реализаций каких либо существующих компонентов системы.
А абстрактный класс это каркас, недостаточный для полноценной реализации какой-либо предметной области, но позволяющий избежать дублирования кода в написании общих элементов однотипных компонентов, унаследованных от этого класса, и возможно, реализующих определенный интерфейс.
 
флоппик
ну это я понимаю, я просто не вижу смысла, да и как-то не встречал примеров одновременного использования интерфейса и абстрактного класса, для описания _одной и той-же сущности_, как в примере Активист'а.
 
zerkms
а если нет необходимости создавать экземпляр класса родителя и ты как бы хочешь, чтоб этот объект нельзя было создать, то не стоит делать его абстрактным? Если родительский класс сам по себе как бы лишен смысла, важны только его наследники?
 
melo
Вот потому, чтобы не было таких тонны "а что если" - нужно задавать вопрос, а не выплёвывать тупо код и предлагать выбрать.
 
Сверху