Hello,
I have a very simple application which consists of an ASP.NET front end site, with a WCF Windows Service doing the heavy lifting back-end logic.
The user has one simple page where he selects some parameters and pushes a 'submit' button. The page calls the WCF service and passes it the parameters. The service instantiated an instance of a 'Job' class, sending the parameters to the constructor, then calls a 'Run()' method which does all the work of - inserting a 'job' record into a database with the users name, time started, etc... Makes a request to a 3rd party vendor, takes the data, puts it in the database, does some other business logic then marks the job as completed.
The user then has a second simple page where he can now search for his job (a searchable combo box sorted by date, displaying multiple fields related to that job) and then display the data corresponding to that job on the screen - (most of the fields from the job table, e.g. started time, completed time, status, etc, displayed as labels in a panel) and the actual data we pulled from the 3rd party vendor (rendered as a grid, below the panel).
Now on to my question - so I have a Job class which has all the fields mentioned above, along with its public Run() method and constructors. It has a few simple private functions, and several private members which are interfaces to classes like IParser, IVendorConnection, IDataAccess - the classes which do all the actual work described above.. the actual Job class and Run() method doesn't do much actual work, pretty much just delegates work to its composite objects (makes for good testability among other things).
Now, this Job class has 3 different possible uses / states. Its main use is inside the Service, for use of the Run() function to literally run a job. It also has 2 other uses - acting as the model for the panel I described above, and acting as a model for the combo box I described above. The job class has 3 public constructors, each one setting it up for one of the 3 states. In all cases, each different 'state' only cares about certain members that the other 2 states don't care about - in some cases some of the members are used in all 3 states. The 'combo box state' is the simplest - in this case I only want 3 readonly fields. In the 'panel state' I care about 6 readonly fields.. in the 'work' state I am basically creating these field values as the job progresses - and they should all be private.
I'm just looking for a cleaner way to do this. If I instantiate a Job class in state A, I know that accessing member X will not work, or calling function Y will fail. However it's still compilable code.
I'm sure that others have faced this problem before. I was thinking of having a base Job class marked as MustInherit/abstract, and then having 3 derived classes, one for each state. Put the shared members in the base and the state-specific ones in the derived, and just use the derived classes in my code where appropriate. This seems simple enough for my purposes and solves my problem. Perhaps I could also have some kind of JobFactory... I guess I'm just looking for how other people solved this as maybe I'm not thinking outside the box enough... I have had many classes be state machines before in my hobbyist game development days - but that was different, because instances of those classes could change states (e.g., an 'Enemy' class could have its state changed from 'attack_mode' to 'waiting') In my case, there is no changing states - once created, a Job must stay in its state and never try to behave in a different one. Tracking state and throwing exceptions if a method/member is used while not in a given state seems brittle and too much work. Any suggestions based on how you have solved this problem before? And is what I'm trying to do overkill? If the Job started to get more and more different states, I would think not - but maybe if it did get that many different states then I need to think of splitting it up into different classes anyway... Just looking for your 2 cents.