Introduction
When I was an MIS engineer, I maintained a schedule system. There are many jobs controlled by auto schedule system, see the example XML file below: Because the XML file is a tree structure, it can describe the job flow cleanly.
<Schedule>
<JobGroup>
<BatchJob id="1" name="job1"></BatchJob>
<BatchJob id="2" name="job2"></BatchJob>
<JobGroup id="3" name="job3">
<BatchJob id="4" name="job3-1"></BatchJob>
<BatchJob id="5" name="job3-2"></BatchJob>
<JobGroup id="6" name="job3-3">
<BatchJob id="7" name="job3-3-1"></BatchJob>
</JobGroup>
</JobGroup>
</JobGroup>
</Schedule>
But how can we build a domain model with a programming language? There is a system design issue.
Background
The code is written in Java, compiled with JavaSE 5. You have to know the concepts of XML, UML and Design Pattern.
Using the Code
How to build a tree structure domain model? I use the composite design pattern!
Consider the following source code:
Job
is an abstract
class and is the parent class of BatchJob
and JobGroup
:
package org.schedulemanager.demo.model;
import java.util.ArrayList;
import java.util.List;
public abstract class Job {
protected String id;
protected String name;
protected String circle;
protected String type;
public final static String BATCHJOB = "BATCHJOB";
public final static String JOBGROUP = "JOBGROUP";
public final static String DAILY = "DAILY";
public final static String WEEKLY = "WEEKLY";
public final static String MONTHLY = "MONTHLY";
public Job(String id) {
this.id = id ;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public abstract void addJob(Job job);
public abstract List<job> getJobList();
}
JobGroup
is a job that does not do anything, it's the child of Job
, but it is also the container of Job
. JobGroup
has a circle field to set the execute time.
package org.schedulemanager.demo.model;
import java.util.ArrayList;
import java.util.List;
public class JobGroup extends Job {
private List<job> jobList;
public JobGroup(String id, String name) {
super(id);
this.type = JOBGROUP;
this.name = name;
jobList = new ArrayList<job>();
}
public JobGroup(String id, String name, String circle) {
this(id, name);
this.circle = circle;
}
public List<job> getJobList() {
return jobList;
}
public void addJob(Job job){
if(job!=null && job.getId()!=null){
jobList.add(job);
}
}
public String getCircle() {
return circle;
}
public void setCircle(String circle) {
this.circle = circle;
}
public boolean removeJob(String id){
boolean result = false;
for(int i=0;i<joblist.size();i++)
{ job="jobList.get(i);" jobid="job.getId();" result="true;"
BatchJob
is a job to do something:
package org.schedulemanager.demo.model;
import java.util.List;
public class BatchJob extends Job {
public BatchJob(String id, String name) {
super(id);
this.type = BATCHJOB;
this.name = name;
}
public void addJob(Job job) {
System.err.println("BatchJob can not addJob!");
}
public List<job> getJobList() {
return null;
}
public String toString() {
return "id:" + id
+ ",name:" + name
+ ",type:" + type ;
}
}
I create a CommandLineView
to display a job flow on the console:
package org.schedulemanager.demo.view;
import java.util.List;
import org.schedulemanager.demo.model.Job;
public class CommandLineView {
private Job job;
public Job getJob() {
return job;
}
public void setJob(Job job) {
this.job = job;
}
public void printAllJobs() {
printAllJobs(job, 0);
}
public void printAllJobs(Job job , int depth) {
List<Job> jobList = job.getJobList();
if(jobList!=null && jobList.size()>0){
for(int i=0;i<jobList.size();i++){
printDepth(depth);
Job subJob = jobList.get(i);
if(subJob.getType().equalsIgnoreCase
(Job.BATCHJOB)){
System.out.print("-");
System.out.println(subJob);
}else if(subJob.getType().equalsIgnoreCase
(Job.JOBGROUP)){
System.out.print("+");
System.out.println(subJob);
printAllJobs(subJob, depth + 1);
}
}
}
}
public void printDepth(int depth) {
for(int i=0;i<depth;i++){
System.out.print("\t");
}
}
}
The manager is responsible to assemble model and view:
package org.schedulemanager.demo;
import org.schedulemanager.demo.model.BatchJob;
import org.schedulemanager.demo.model.JobGroup;
import org.schedulemanager.demo.model.Job;
import org.schedulemanager.demo.view.CommandLineView;
public class Manager {
private Job rootJob;
public Manager() {
initJobs();
}
public void initJobs(){
rootJob = new JobGroup("0", "rootJob",Job.DAILY);
Job job1 = new BatchJob("1","job1");
Job job2 = new BatchJob("2","job2");
Job job3 = new JobGroup("3","job3",Job.DAILY);
Job job4 = new BatchJob("4","job3-1");
Job job5 = new BatchJob("5","job3-2");
Job job6 = new JobGroup("6","job3-3",Job.DAILY);
Job job7 = new BatchJob("7","job3-3-1");
Job job8 = new BatchJob("8","job4");
Job job9 = new BatchJob("9","job5");
job6.addJob(job7);
job3.addJob(job4);
job3.addJob(job5);
job3.addJob(job6);
job3.addJob(job8);
rootJob.addJob(job1);
rootJob.addJob(job2);
rootJob.addJob(job3);
rootJob.addJob(job9);
}
public void run(){
CommandLineView view = new CommandLineView();
view.setJob(rootJob);
view.printAllJobs();
}
public static void main(String[] args) {
Manager manager = new Manager();
manager.run();
}
}
The running result is shown below:
You can also create other view (Web, GUI, etc.) easily with the domain model.
Points of Interest
Think about job dependency! Batch Job is in sequence. So the job dependency is an important issue. Our tree domain model is with scalability, we can add the job class dependencyList
field. The additional UML is shown below:
Summary
Thinking about this tree structure domain model, it can be useful with many practices, for example: project manage tool, file system, tree GUI, etc. Don't only think about the recursion algorithm to display tree structure, we can think and design more Object-Oriented by creating the domain model first.