Отдельная логика от класса, когда данные инициализируются в конструкторе

Если у меня есть Car класс как это:

class Car
{
/**
* @var string $model
*/
private $model;

/**
* Makes a new car based on a model
*
* @param string $model Initializes the model
*/
public function __construct($model) {
$this->model = $model;
}

/**
* Gets the car model
*
* @return string The model
*/
public function getModel() {
return $this->model;
}
}

И CarValidator как это:

class CarValidator
{
public function isValidated(Car $car) {
if (empty($car->getModel())) {
return false;
}
return true;
}
}

И мое использование так:

$bmw = new Car('bmw');

Как мне проверить мой автомобиль BMW перед его созданием?

1

Решение

На мой взгляд, у вас есть 2 варианта.

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

Что из этого наиболее применимо, я думаю, что в основном все сводится к тому, что является «действительным» в вашей ситуации и является ли валидность универсально применимой. Правда, вероятно, означает немного и того, и другого.

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

Валидатор может проверить, что автомобиль действителен после постройки, чтобы убедиться, что указанная модель / цветовая комбинация существует в данный момент. Эти правила могут измениться, и поэтому они будут более применимы к внешней валидации (у вас может быть другая приемлемая модель в некоторых странах или другие правила валидации, основанные на некоторых других факторах). Они могут жить в вашем CarValidator класс (ы).

Любые фундаментальные инварианты вашего объекта, на которые будут опираться части вашей программы (например, тот факт, что модель не пустая), должны проверяться и применяться самим объектом, так как это не «бизнес-правила» как таковые, а инварианты система.

Я бы, вероятно, пошел с:

public class CarFactory
{
private ICarValidator validator;
public CarFactory(ICarValidator validator){ this.validator=validator;}

public Car Create(string model)
{
Car car = new Car(model);
if (validator.IsValid(car))
return car;
throw new InvalidCarException(car);
}
}

public Car
{
private string model;
public Car(string model)
{
if (model=="")
throw new EmptyModelException();
this.model=model;
}
}

Что дает вам разделение ваших инвариантов (обеспечивается Car) из вашей бизнес-логики (заключено в CarValidator) и запрещает вашим пользователям получать недействительные экземпляры автомобиля вообще.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]