@Danbka

Как создавать объект с большим количеством свойств?

Привет.

Для иллюстрации вопроса я приведу сферический пример в вакууме.

Есть класс, задача которого - записывать данные о продукте в файл. Метод write() принимает в качестве параметра объект класса Product и уверен, что в объекте есть нужные свойства.

Class ProductWriter
{
	public function write(Product $product)
	{
		// write to file
	}
}


Product имеет много свойств (порядка 20): название, описание, цена, размер, цвет, форма и т.д. и т.п. Причем часть свойств - обязательна, часть - опциональна.

Как оптимально написать класс Product?

Мои варианты:

1) Конструктор класса Product принимает ассоциативный массив параметров. В конструкторе проверяется наличие обязательных полей. Мне кажется этот способ не самым лучшим: клиентский код не знает, какие ключи должны присутствовать во входном массиве.

2) Создать кучу свойств и геттеров/сеттеров для них:
Class Product
{
	private $name;
	private $price;
	// ...

	public function setName() {}
	public function setPrice() {}
	// ...

	public function getName() {}
	public function getPrice() {}
	// ...
}


Но опять же - откуда клиентскому коду знать, что после создания объекта нужно обязательно вызвать некоторые сеттеры?

$product = new Product();
$product->setName('name');
$product->setPrice('0.0');


3) Ну и самый треш - конструктор с 20 параметрами:
Class Product
{
	function __construct($name, $price, $color, $size, ....)
	{

	}
}


Так, конечно, клиенсткий код точно укажет все обязательные поля. Но так делать не стоит, в книжках написано))

Если говорить о вариантах №1 и №2: на самом деле этим классом никто кроме меня самого пользоваться не будет. А я то точно знаю, что нужно заполнить о продукта. Но хотелось бы решить задачу "красиво".

PS. Предвижу комментарии в духе: почему один общий класс продукт? Создай подклассы только с нужными свойствами и будет тебе счастье.
На это отвечу, что мой пример с продуктом - условный. В моем случае действительно сущность с кучей свойств, от которой нельзя ничего унаследовать и разбить на более простые сущности.
  • Вопрос задан
  • 1549 просмотров
Решения вопроса 1
qonand
@qonand
Software Engineer
Обязательные параметры стоит задавать в конструкторе класса - это позволит обеспечить обязательность их указания, опциональные с помощью геттеров и сеттеров. Кроме того стоит пересмотреть действительно ли все обязательные поля являются обязательными - или некоторые все таки нет + по возможности параметры стоит упаковать в объекты-значения
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
sergiks
@sergiks Куратор тега PHP
♬♬
Принимать ассоциативный массив. Недостающие свойства дописывать дефолтными значениями или тошнить exception когда пропущено обязательное свойство.
Ответ написан
ApeCoder
@ApeCoder
Посмотреть нет ли взаимосвязи между свойствами. Возможно есть группы связанных свойств, которые можно выделить в отдельные классы.

Обязательные свойства - параметрами конструктора, остальные свойствами.

Посмотреть также паттерны создания, например фабричный метод и билдер.
Ответ написан
Комментировать
@Zanak
Я бы разбил задачу на 2 части: создание объекта и его использование.
Создание объекта:
- Кроме обязательных, могут быть условно обязательные (это в случае, когда задание одного параметра делает обязательным еще какое - то количество параметров) и опциональные.
- Когда все параметры обязательны, то пишем конструктор.
- Инициализацию условно обязательных параметров может иметь смысл обернуть вспомогательным классом, который можно сделать доступным только в контексте основного класса, и в его реализацию включить проверку переданных параметров.
- Постройку классов с условно обязательными и опциональными параметрами, кроме прямого разбора параметров, можно реализовать с помощью фабрик, которые будут содержать меньшее число параметров, и устанавливать опущенные в корректные значения по умолчанию.
- Вместо фабрики можно скрыть ваш класс за фасадом с более простым интерфейсом.
- Так же, можно создать несколько методов постройки объекта, а конструктор реализовать в виде диспетчера, который вызовет нужный, в зависимости от переданных параметров.
Использование объетов:
- Для условно обязательных параметров не избежать создания методов, которые принимают весь кортеж связанных между собой параметров. Это вместо отдельных сеттеров для каждого свойства.
- Кроме set/get методов доступа можно использовать прямой доступ к свойствам, всем или некоторым, особенно, если есть взаимная зависимость параметров, и создания полноценного валидатора для всего набора параметров конструктора не избежать.

Если отвечать наиболее обще, то я бы поступил как - то так.
Ответ написан
Комментировать
php666
@php666
PHP-макака
$product = new Product();
$product->setData($data); // $data - массив со значениями. 
// Берем ключи каждого элемента $data, приводим к camelCase, пытаемся найти такой set-метод 
// в объекте product и вызвать его с относящимся к ключу значением
print_r($product->getModelErrors()); // проверяем, насколько корректно заполнен продукт

как работает getModelErrors: у класса product есть некая карта допустимых свойств модели. Обязательное ли свойство или нет. Если нет, то какое дефолтное значение. Можно навесить валидацию на каждое из описанных свойств. Т.е. создать систему валидаторов и к каждому свойству применять от 0 до бесконечного множества различных валидаторов. У меня в фреймворке это сделано так.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы