Обработка состояния дочернего объекта, когда оно влияет на родительское состояние

#java #oop #design-patterns

#java #ооп #шаблоны проектирования

Вопрос:

Пример:

 class Person
{        
    @OneToMany
    List<Action> actionHistory;

    @ManyToOne
    Employer  employer;

    private StateEnum myCurrentState = StateEnum.INITIAL_STATE;
 }
  

Представьте себе ситуацию, подобную этой, где верны две вещи:

  1. Person.myCurrentState необходимо изменить в ответ на изменения в actionHistory, employer и т.д. Существует набор бизнес-правил типа «Если действие типа X отображается в потоке действий, а текущий статус равен Y, тогда установите новый статус на Z»

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

Изначально я думал, что просто попытаюсь перенаправить весь доступ к дочерним элементам через процедуры лично, которые содержат validation / reactionlogic. Результатом было то, что объект Person стал слишком большим и повсюду, из-за того, сколько дочерних операций ему нужно было отслеживать. (Т.Е. вместо просто getAEmployer(), setNewEmployer () и тому подобного, это также такие вещи, как updateJobTitleAtEmployer() и т.д.)

Хотя распространение логики на дочерние элементы кажется столь же беспорядочным. В этом случае Employer (например) должен содержать тонны ссылок на своего родителя. Также бизнес-правила, связанные с этим материалом, разбросаны повсюду.

Есть ли какое-нибудь чистое общее решение этой проблемы? Мне бы хотелось каким-нибудь общим способом проверить родительский класс и в некоторых случаях реагировать на определенные изменения состояния многих его дочерних элементов.

ОБНОВЛЕНИЕ: я думаю, что я неправильно использовал термины «Родитель» и «Потомок» в этом вопросе. Я использую их следующим образом: Parent «имеет «дочерний элемент / Parent «, состоящий из дочернего элемента». В примере Person будет родительским классом, а классы свойств будут дочерними.

Лучший пример:

 class Employee
{
    private Contract contract;
    private List<Action> actions;

    private EmployeeState currentState = EmployeeState.INITIAL; 
}
  

Представьте в этом случае, что currentState может измениться, если что-то изменится в контракте (например, если скорость повысится). Также может случиться так, что определенные параметры не могут быть установлены в контракте, если сотрудник находится в определенных состояниях. В случаях, когда currentState изменяется, свойства контракта являются лишь одним фактором в более масштабном вычислении (т. Е. состояние может определяться правилами типа «если Contract.hourlyRate > 30 и actions содержит действие с этими свойствами, чем state is …»).

Кроме того, в этом случае добавление действия может изменить состояние Employee или быть заблокировано в зависимости от текущего состояния.

Вероятно ли, что с моей моделью что-то не так, если я сталкиваюсь с этими проблемами?

Комментарии:

1. Я просто хочу убедиться, что терминология понятна — когда вы говорите «родительский» и «дочерний» здесь, вы используете это для обозначения элементов данных («дочерний», ( Employer ) является членом «родительского» ( Person ))? Я спрашиваю, потому что я привык слышать, что «родитель» и «потомок» используются в смысле иерархии наследования — дочерним элементом Person будет класс, который расширяется Person . Но, похоже, это не то, что вы здесь имеете в виду.

2. Да, я думаю, что неправильно использую эти термины. В этом случае я использую «дочерний» для обозначения класса, который находится внутри родительского. (Таким образом, родительский тип имеет отношение типа «имеет a» или «состоит из» с дочерним типом).

3. Я все еще смущен вашим примером. Я думаю о названии должности как о свойстве сотрудника / персоны, а не работодателя / компании. Если название должности зависит от состояния пользователя, то функция setJobTitle должна просто проверять это состояние.

4. Вы правы. Мне действительно следовало немного больше продумать пример. Возможно, лучшим примером может быть отраслевая собственность am на employer. Когда это изменяется, это может что-то изменить в состоянии объекта Person или быть заблокировано вообще.

Ответ №1:

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