Постепенно заполните объект (правильный дизайн?) - PullRequest
2 голосов
/ 04 декабря 2011

Общая проблема

У меня есть некоторые объекты, у которых есть переменные, которые не известны во время создания.

Сейчас я создаю эти объекты и постепенно заполняю их, пока они не будут полностью созданы.Но мне интересно: «Это хороший дизайн - постепенно заполнять объект, пока он не будет полностью создан?».

Моя конкретная проблема

Я разрабатываю программу на Java, которая имеетиерархия объектов Task .Эти задачи имеют некоторые переменные, которые известны, когда я их создаю, и некоторые переменные, которые становятся известны только тогда, когда задача запланирована.Прямо сейчас я создаю эти задачи с известными переменными, и когда задача готова к планированию, я вызываю scheduleTask (Task t) , и этот метод устанавливает переменные, которые становятся известны, когда задача запланирована.

Но является ли это хорошим решением для создания объектов, которые не были полностью созданы, и установки оставшихся переменных, когда они станут известны?

Я думал об отсрочке создания задачи до тех пор, пока все переменные не будутизвестно (когда это запланировано).Но некоторые задачи могут быть запланированы только после получения одобрения от внешних источников.

Есть ли у кого-нибудь идеи для решения этой проблемы?

РЕДАКТИРОВАТЬ : я забылупомянуть, что у меня есть различные типы задач, которые все наследуются от «Задачи».

РЕДАКТИРОВАТЬ 2 : Как насчет объектов «ProposedTask», которые имеют переменные, которые были известны до планирования?Ссылки на них можно хранить до тех пор, пока не получит одобрение.Затем при планировании можно создать новую «задачу» на основе объекта «ProposedTask» («scheduleTask (ProposedTask p)» теперь принимает объект ProposedTask).

Ответы [ 6 ]

3 голосов
/ 04 декабря 2011

Используйте шаблон Builder.Например:

Task.Builder b = new Task.Builder():
b.knownProperty(value).anotherProperty(value2);

myExecutor.schedule(b);


...
void schedule(Task.Builder b) {
    b.propertyBeforeExecute(value);
    Task t = b.build();
}

Многие фреймворки используют его для создания частично созданных объектов, а затем выполняют некоторые действия.Например: Http запрашивает сборщиков -> HttpPool executors

1 голос
/ 04 декабря 2011

Если ваш класс сложный, чтобы упростить проверку состояния и разделить недопустимое состояние, рассмотрите возможность помещения всех полей TBD в отдельный класс (возможно, просто внутренний класс). Затем установите для него значение null или используйте метод readyToGo (), и будет проще проверить, были ли они заполнены или нет. Ваш объект задачи будет иметь стабильное, действительное состояние. например (пропуская множество геттеров и сеттеров, они могут и не понадобиться, используйте пакетный доступ)

public class Task {

   final int known1;           // the final is optional but I usually use it
   final String known2;
   final TBD tbd = new TBD();  // might be transient depending on your persistance???

   public Task(int known1, String known2) {
      this.known1 = known1;
      this.known2 = known2;
   }

   public void submit() {
      if (!tbd.readyToRun())
         throw new IllegalStateException();
      // do real work here...
   }

   public void setTBDSomething(int something) { tbd.something = something; }
   public void setTBDStartDate(Date startWhen) { tbd.startWhen = startWhen; }


   class TBD {
      int something;
      Date startWhen;

      boolean readyToRun() { // Dixie Chicks music optional...
         return something > 0 && startWhen != null;
      }
   }

}
1 голос
/ 04 декабря 2011

Вы можете сделать это, если это имеет смысл для вас ....

Чтобы инициализировать переменные в объекте и заполнить их позже, вы можете установить для них значение null

public class MyClass {
 public int firstvar=null;
 public String secondvar=null;

 public String useVars() {
   if(firstvar!=null && secondvar!=null)return firstvar+" "+secondvar;
   else return null;
 }
}
public class Main {
 MyClass m;
 String result;
 public void runIt(){
  m=new MyClass();
  m.firstvar=5;
  result=m.useVars();
 }

 public void doLater(){
  m.secontvar="hello";
  result=m.useVars();
 }
}

Чтобы быть еще более необычным, вы можете использовать пользовательские исключения .....

public String useVars throws MyCustomException(){ /* .... */ 
 if(firstvar==null || secondvar==null)throw new MyCustomException("ERROR!!!!!!!");
}


public class MyCustomException extends Exception {
 public CustomException(String s){ super(s);}
}
0 голосов
/ 07 января 2012

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

У меня появилось такое ощущение, когда я подумал: «Я создаю задачу типа ProposedTask, и теперь этозапланировано. Запланированная задача "Это сбивает с толку.И мой мозг поражается, когда я думаю обо всех типах типов, создании новых объектов различного типа как концептуальная задача , изменяющая состояние .

То, что я вижу, - это задачи (в общем смысле), которые переходят от «предложенных» к «запланированным» или «отклоненным», туда-сюда и т. Д. Тип (объекта) не должен изменяться, состояние объекта должно изменяться.

Если это удачное предположение с моей стороны, я бы ожидал иметь один тип Task со всеми возможными переменными, объявленными в нем.Добавьте свойство myState.В каждом состоянии («Предложено», «Запланировано») определенные переменные получают свои значения.

0 голосов
/ 04 декабря 2011

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

Если вам нужно сериализовать ваш объект и вам нужен пустой конструктор + методы получения сеттеров используют шаблон проектирования Memento и выполняют сериализацию, используя сувениры этого объекта.

0 голосов
/ 04 декабря 2011

Вы можете предоставить метод экземпляра checkStatus классу Task, который будет возвращать состояние объекта задачи, чтобы узнать, полностью ли он создан и готов к планированию.

Любой клиентский код может использовать этот метод и принимать соответствующие решения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...