逐渐填充物体(正确的设计?)

时间:2011-12-03 23:37:19

标签: java oop design-patterns

一般问题

我有一些对象有一些在创建时不知道的变量。

现在我创建这些对象并逐渐填充它们,直到它们被完全实例化。但是我想知道,“在完全实例化之前逐渐填充对象是否是一个好的设计?”。

我的具体问题

我正在开发一个具有 Task 对象层次结构的Java程序。这些任务包含一些在创建它们时已知的变量,以及一些仅在调度任务时才知道的变量。现在我使用已知的变量创建这些任务,当任务准备好进行调度时,我调用 scheduleTask(任务t),此方法将设置在任务正在进行时已知的变量调度。

但它是一个很好的解决方案来创建未完全实例化的对象,并在知道它们时设置剩余的变量吗?

我在考虑推迟创建任务,直到所有变量都已知(正在调度时)。但是,只有在获得外部来源的批准后才能安排一些接收。

有人对如何解决这个问题有一些设计思路吗?

编辑:我忘了提到我有从“任务”继承的不同类型的任务。

EDIT 2 :具有调度前已知变量的“ProposedTask”对象怎么样?在获得批准之前,可以保留对这些内容的引用。然后可以创建一个新的“任务”,同时基于“ProposedTask”对象进行调度('scheduleTask(ProposedTask p)'现在采用ProposedTask对象。)

6 个答案:

答案 0 :(得分:3)

使用Builder模式。 E.g:

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执行器

答案 1 :(得分:1)

如果对你有意义,你可以这样做....

要初始化对象中的变量并在以后填充它们,可以将它们设置为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);}
}

答案 2 :(得分:1)

如果您的类很复杂,为了简化状态检查并划分无效状态,请考虑将所有TBD字段放入一个单独的类(可能只是一个内部类)。然后将其设置为null,或者让它实现readyToGo()方法,并且如果它们已被填充,则更容易检查。您的Task对象将具有稳定,有效的状态。例如(跳过许多getter和setter,无论如何都可能不需要它们,使用包访问)

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;
      }
   }

}

答案 3 :(得分:0)

您可以向Task类提供checkStatus实例方法,该方法将返回任务对象的状态,以了解它是否已完全实例化并准备好进行调度。

任何客户端代码都可以使用此方法并相应地做出决定。

答案 4 :(得分:0)

在我看来,生成具有无效状态的对象是一种不好的做法。这种情况下的主要缺点是每次使用时都需要检查一个对象。我更喜欢在构造函数上初始化状态并传递所有需要的参数以便生成有效状态,并在构造函数中出现任何错误时抛出异常,因此在这种情况下,您将确保每次使用对象时它将处于有效状态,您可以安全地使用它。

如果你需要序列化你的对象并需要一个空的构造函数+ setter getters使用Memento设计模式并使用这个对象的memento进行序列化。

答案 5 :(得分:0)

我的印象是您需要进一步分析您正在建模的业务领域/流程。听起来您正在尝试通过更改流程中每个步骤的对象类型来建模工作流程。

当我想到“我创建了一个ProposedTask类型的任务,现在已经安排好了。我已经安排好了。这是一个预定的ProposedTask”这令人困惑。当我想到所有的类型转换,创建新的不同类型的对象时,我的大脑都会感到困惑,因为概念任务 改变状态

我看到的是任务(一般意义上说)从“建议”到“预定”或“不批准”,来回等等。(对象的)类型不应该改变,对象的状态应该。

如果这是我的一个很好的猜测,那么我希望有一个单一的Task类型,其中声明了所有可能的变量。添加“myState”属性。在每个州(“Proposed”,“Scheduled”)中,特定变量得到它们的值。

相关问题