User:Chen Qing

From CSSEMediaWiki
(Difference between revisions)
Jump to: navigation, search
(Source Code)
 
(11 intermediate revisions by one user not shown)
Line 6: Line 6:
  
 
=== Main Design Decisions ===
 
=== Main Design Decisions ===
 +
 +
The design can be break into three major parts: print product family, print job & job workflow and print company structure itself. I will analyse the design separately in the following section.
  
 
==== Print Product Family ====
 
==== Print Product Family ====
  
A good point for start is to model the actual print products produced by the company. At present, there are two main types of print products, one is single sheet/page product, and the other is multiple sheet/page products. The example we chosen to model here are book, business card, NCR booklet and pad. The type of the print product is limited by the actual hardware (printing machine) and employee skill sets. All of the print products are share some common properties and also has some unique properties. The design for this part is illustrated in Figure 1.
+
A good point for start is to model the actual print products produced by the company. At present, there are two main types of print products, one is single sheet/page product, and the other is multiple sheet/page products. The example we chosen to model here are book, business card, NCR booklet and pad. The type of the print product is limited by the actual hardware (printing machine) and employee skill sets. All of the print products are share some common properties and also has some unique properties. The design for this part is illustrated in Figure 1. ''(Note: for the readability of the UML class diagram, some of the method parameters and return types are not shown.)''
  
 
[[image:PrintProduction_Products.jpg|thumb|800px|centre|'''Figure 1: Print Product Overview]]
 
[[image:PrintProduction_Products.jpg|thumb|800px|centre|'''Figure 1: Print Product Overview]]
Line 17: Line 19:
 
In order to handle the creation of these concrete print product classes, the [[Abstract Factory]] and [[Factory Method]] pattern are used here. These patterns can provide client a unified interface for create those concrete print product. In the actual implementation, the createPrintProduct method will take all the properties required by a PrintProduct, and depends on which particular concrete factory object the client is using, it will only initialize those properties which are valid towards the concrete print product.
 
In order to handle the creation of these concrete print product classes, the [[Abstract Factory]] and [[Factory Method]] pattern are used here. These patterns can provide client a unified interface for create those concrete print product. In the actual implementation, the createPrintProduct method will take all the properties required by a PrintProduct, and depends on which particular concrete factory object the client is using, it will only initialize those properties which are valid towards the concrete print product.
  
 +
An Enumeration PrintProductType is later on introduced. This covers all the current print product types. If customer decide to add new print product type, for instance, map, the changes need to do is just introduce a new print product type, a new concrete print product class and a new factory class associated with it. The print product interface (abstract class PrintProduct) will not be changed very often as explained earlier (machine limitation, employee skill sets etc.), if there is a change for the interface, it is also a sign that there is a couple more other things might be affected. In that situation, reworking on the interface is a much better idea.
  
 +
An argument was raised when I was working on this design; it is whether the print product interface should be considered as too "fat". A notice here is for simple print product such as business card, it has to carry a lot of extra properties when it is used with this interface. In the actual implementation, it is possible for client to use a property which does not belong to business card. Different from the first design attempt, which basically code up a no-op function for such properties, in the new design an unsupported operation exception has been introduced to couple with this problem. I think a trade off has to be made here for using a uniformed print product interface.
  
 +
As the result of this “fat” interface, the creation of each concrete print product object also needs to fill a lot of parameters in order to initialize a concrete print product properly. The decision for this version of the design is introduce "fat" constructors and only initialize appropriate properties by each individual concrete factory object. An alternative of this is to only initialize the common properties for all the current products, then ask client code to initialize the other necessary properties for a field. The danger for this approach is that assumption of client fully initialize a concrete product object properly has to be made, which might not always be the case. The [[Facade]] pattern might be applied here to guide/organize all the product creation, but there still need a way to pass in those required parameters at some stage. Since there isn’t a clear win of this approach, I stayed with the existing design.
  
 +
===== Used Design Patterns =====
  
 +
* [[Decorator]]
 +
* [[Factory Method]]
 +
* [[Abstract Factory]]
  
PrintCompany class is the main class used to represent the printing company. The company holds references to its customers, employees, external contractors (this is quite often used for some design works), and departments. The print company also has a job queue which is used to track all the jobs. Object PrintJob is used to represents each individual print job (their orders). For each individual print job, it could have one or more final print products. Also for each print job, there is a state associated with (i.e. in quoting state, in designing state and in pressing state etc.). The design details for print job and print products are illustrated in Figure 2.
+
===== Applied Design Principles =====
  
[[image:JobAndProduct.jpg|thumb|800px|centre|'''Figure 2: Print Job and Print Product Overview]]
+
* [[Dependency inversion principle]] The PrintProduct abstract class acts as the interface for all the concrete print products for client object.
 +
* [[Open closed principle]] PrintProduct interface can be extended with new concrete print product class
  
 +
===== Violdated Design Principles =====
  
=== Main Design Decisions ===
+
* [[Fat interfaces]]
 +
* Method with large number of parameters
  
==== Print Job State Capture ====
+
==== Print Job and Print Job Workflow ====
  
The state for a print job originally is used for system tracking purpose; it is also evolved to provide a precious cost calculation function for each stage of the printing process. In ordinary situation, the company and customer will agree on one quoted price for the entire job, therefore, knowing the actual cost of each job in each printing stage (state) becomes critical. However, the cost calculation method for each state, which is usually done by different department, is drastically different. In order to control the differences in the cost calculation and also maintain a unified interface to the PrintJob, the [[State]] pattern is used here.
+
[[image:PrintProduction_PrintJob.jpg|thumb|800px|centre|'''Figure 2: Print Job Overview]]
  
==== Family of the Print Product ====
+
As you might guessed already, the print company has a job queue which records all the jobs in the company. These set ups are modelled as class PrintJob and JobQueue. For each print job they had, there would be a number of print product associated with it. An ArrayList is used to store the products for a job in the implementation, the [[Iterator]] is used to iterator through the print products list.
  
Various kinds of printing product are produced by the company, and there is going to be new print product added/old print product removed once a while. In order to cope with this requirement and decouple the relationship between client class and concrete print product classes, a common interface PrintProduct is introduced. The print products have been categorized into the single page product, and multiple page products. Examples of them are business card, pad, book, and NCR booklet. The [[Composite]] pattern is used here and with all the essential attributes required by all concrete print product classes, so the client class can deal with different concrete product in a uniformed way. Corresponding to the code, PrintProduct interface is the ‘component’, Booklet abstract class is the ‘composite’ and we had BusinessCard, Pad, Book, and NCRBooklet as the ‘leaf’ classes.
+
For each job, it also has a state field to record which stage of the job is in currently. Typical stages here are quote, design, press (printing), finishing and dispatch. Since there is a requirement to calculate the cost for these states, and the calculation algorithm for each state is different, the [[State]] pattern is used here. Another benefit with applying the [[State]] pattern here is it also leaves the possibility for adding new state / drop existing state as the company’s business procedure evolves. The state transition for a job is handled by JobStateHandler interface. Currently, there are two state transition patterns existed for the company, one is for jobs which require external designer to do the design stage, another is for normal print jobs. The state transition is also seen as a frequent change candidate, so the [[Strategy]] pattern is used here. A JobStateHandler is bind to the job itself, and the concrete handler for each job object will direct the job to follow the right state transition path.
  
However, some problems have been identified with this design, see Problem Yet To Be Solved for more details.
+
One unsolved problem with this part of the design is the code duplication for get quote price in QuoteState and cost method for other state classes. In theory, the quote should be close to the sum of actual costs which will occur later in each state. Currently, the same algorithm is shared between quote state and other states, as the result, the code duplication occurs. Some other design tricks might be used here for improving this, but I do notice a fact that in the finished system, the quote calculation might not have the same access to a large number of fields which other production state could access. Furthermore, it is wise to say we do not want to use the exactly same algorithm for calculating the quote and the cost for each stage. The cost for each stage is aimed at more accurate actual production cost, and the algorithm for quote should not require a lot of detailed information.
  
==== Job Queue Observing ====
+
===== Used Design Patterns =====
The print company has a job queue used to track all the current jobs, this enable client to know which state of a particular job is in. Department and other people necessary for a print job (i.e. external contractor). Each department and external contractor has a current job queue referencing to all jobs in the company job queue but only the content needed for them. Once the main company job queue gets updated, we also want the current job queue gets updated.  The [[Observer]] pattern is used in this case. However, currently there is no content filter for the job queue, which is not acceptable, see Job Queue Observing Content Filter under Problems Yet To Be Solved for more details.
+
  
==== One instance of Print Company and Job Queue====
+
* [[State]]
To ensure all the client code is talking to one and only print company and job queue across the application. The [[Singleton]] pattern is used to ensure this.
+
* [[Strategy]]
 +
* [[Iterator]]
  
 +
===== Applied Design Principles =====
  
 +
* [[Dependency inversion principle]] The State interface provide a common interface for client code to interact with any concrete state class.
 +
* [[Open closed principle]] State and JobStateHanlder enables new state and state handler to be added easily.
  
=== Problems Yet To Be Solved ===
+
===== Violdated Design Principles =====
  
''(Hopefully all the problems identified will be solved before the due date.)''
+
* [[Duplicate Code Smell]]
  
==== Flow of State Transition ====
 
  
The control for the flow of state transition is currently depended on client code to call the set method to set to the new state while all jobs in the old state are finished. Customer requires the application to be able to transit the job state to a new job state once the work for previous job is finished. Furthermore, not all jobs will require all states.
+
==== Print Company Structure ====
  
==== Noop Operation ====
+
[[image:PrintProduction_PrintCompany.jpg|thumb|800px|centre|'''Figure 3: Print Company Structure]]
  
For the print product family design, the [[Composite]] is used for provide a uniformed interface for client classes who needs to work with any concrete print products. However, not all properties of the common interface are valid for all the concrete products. For example number of pages (numOfPages) doesn’t make sense for business card, drillHoles does not make any sense for a book, number of leaves only make sense on NCR booklet. In the implementation of the concrete children classes, the irrelevant methods are done as no-operation method to conform the interface. However, in reality, there are far more unique properties for each kind of print product, we will ends up with huge number of no-operation method. We know we have to face the tradeoffs in the real world, but for a simple business card to include another one hundred properties which only valid for a book is seemed to be too much. Probably a better design should be provided here.
+
As any typical company, the print company consist of a number of employees, departments, customers and in this case external contractors. A Person class is introduced to handle some of the common parts between employees and external contractors. The person class is also used for contactor person in Customer class. The design of the Person class here is more about reduce code duplication rather than providing a common interface, hence Person class is a concrete class in the actual implementation.
  
==== Content Filter for Job Queue Observing ====
+
As mentioned earlier, there is a JobQueue in the company to hold all the jobs it has. A number of jobs are stored in there. The actual implementation for this job queue is done with ArrayList, and [[Iterator]] is used here again. Departments and external contractors need to watch this job queue closely all the time. The [[Observer]] pattern is used here with JobQueue as subject, Department and ExternalContractor are used as the observer. Every time job queue changes, departments and external contractors will be noticed and they can re-fetch a job queue from the company. As this system now is still in development stage, the performance hasn’t been a problem for frequent job queue changes. Based on the knowledge of customer, there will be no frequent job queue changes at this stage, but it would be a potential problem in future if the work load for this application increased sharply. The alternative approach for this is to set up a timer and refresh job queue by a pre-set time frequency. This design will lose the real time watching function for the application so the original design is used, but this part of the design still need to be watched closely if there is a performance problem in future.
The [[Observer]] pattern only provides us a way to ensure department and external contractor get notified when job queue changes, however, we need the change reports to be different based on received roles. Using [[Strategy]] to encapsulate the get job queue seems to be a better choice (working on progress).
+
  
==== Design for the Data Access Layer ====
+
For security reasons, we do not want external contractor to see the same job queue as departments could do. However, there is also no need for maintaining a different or sub job queue for this purpose alone. The [[Proxy]] pattern is used (access control proxy) here to control the access for departments and external contractors. As a result, external contractor will not be able to invoke the getQueue method aimed at internal employees.
''Coming soon ...''
+
  
==== Print Product Creation ====
+
Lastly, we only need one instance of print company, which is the owner object for everything else in the application, so the [[Singleton]] pattern is used here. The [[Singleton]] is not directly applied to JobQueue since the implementation ensures print company will initialize the unique job queue and other object will get the job queue through the print company.
''Coming soon ...''
+
  
 +
===== Used Design Patterns =====
  
 
=== Used Design Patterns ===
 
 
The design pattern used so far are:
 
* [[Composite]]
 
 
* [[Observer]]
 
* [[Observer]]
 +
* [[Proxy]] The access control proxy is used here, the implementation is done with Java InvocationHandler.
 
* [[Singleton]]
 
* [[Singleton]]
* [[State]]
+
* [[Iterator]]
 +
 
 +
===== Applied Design Principles =====
 +
 
 +
 
 +
===== Violdated Design Principles =====
 +
 
 +
* [[Avoid concrete base class]] The Person class is a concrete base class for Employee and ExternalContractor.
 +
* [[Law of demeter]] JobQeueu is retrieved from PrintCompany when used by client classes. This is used for ensuring the uniqueness of the JobQueue in the application without using the [[Singleton]] pattern for both PrintCompany and JobQueue.
 +
 
 +
 
 +
==== Dropped the Composite Pattern Used by the First Attempt ====
 +
 
 +
[[image:JobAndProduct.jpg|thumb|800px|centre|'''Figure 4: Old Design (First Attempt, Dropped)]]
 +
 
 +
In the first attempt, the [[Composite]] pattern was used for the print product family. The reason for using it at that time is for given a consistent interface for client code to use, i.e. define the interface with PrintProduct abstract class. Later analysis found that what it is really needed is actually a [[Decorator]] pattern. This is provided as we had the PrintProduct interface already. The actual print product object only provides more behaviours to the defined functionality in the interface. A more direct reason for dropping the [[Composite]] design is due to the design I had did not conforms to a part and component relationship, furthermore, the composition brought in by [[Composite]] (component node) does not bring more benefit to the application, for keeping things simple, the [[Decorator]] is used here.
 +
 
 +
=== Implementation Notes ===
 +
 
 +
Different from the original vba code based application, the design is coded in Java 1.5. Generic is not used for the final submission due to a UML tool limitation. Some of the interesting topic encountered during the development are organized below.
 +
 
 +
==== Thread Safe Singleton Creation ====
 +
 
 +
A thread safe getInstance() method for [[Singleton]] pattern used with PrintCompany class is applied in the implementation. An interesting read can be found from
 +
 
 +
http://www-128.ibm.com/developerworks/java/library/j-dcl.html
 +
 
 +
=== Source Code ===
 +
 
 +
Please see the attached zip file for the source. [[Media:PrintProduction.zip]]
 +
 
 +
[[image:PrintProduction.jpg|thumb|800px|centre|'''Figure 5: Print Product Overview]]
 +
 
 +
=== Future Work ===
  
=== Violated General Design Principles ===
+
As this project is still evolving, more work on the design might be added. The next big task for this project is to design the data access layer strcuture. As most of the typical business applications, database interaction is one of the core part of the application. I will keep working on this over next month. In the meanwhile, I will seeking for better solution for the duplicate code problem this application had with the quote calculation.
''Coming soon.....''
+

Latest revision as of 03:58, 1 October 2008

Hello everyone, welcome to my home page. I am a 2008 cosc427 student.

Contents

Design Study

Recently I have built a “quick and dirty” MS Access based VBA application for a friend. The application is for helping a small printing company to maintain their job records, organize their job flow and providing some reporting function etc. I thought this is a good case to exercises what we have learned through the cosc427 lectures (and also past courses), so I reworked on this application and will build it within an object-oriented environment. This application also connects to a backend database, for the purpose of this design study, I will only consider the basic structure for the business logic layer.

Main Design Decisions

The design can be break into three major parts: print product family, print job & job workflow and print company structure itself. I will analyse the design separately in the following section.

Print Product Family

A good point for start is to model the actual print products produced by the company. At present, there are two main types of print products, one is single sheet/page product, and the other is multiple sheet/page products. The example we chosen to model here are book, business card, NCR booklet and pad. The type of the print product is limited by the actual hardware (printing machine) and employee skill sets. All of the print products are share some common properties and also has some unique properties. The design for this part is illustrated in Figure 1. (Note: for the readability of the UML class diagram, some of the method parameters and return types are not shown.)

Figure 1: Print Product Overview

A common interface for print product (abstract class PrintProduct) is defined. This interface contains all the properties which a print product could contain (and which can be produced by this company). The Decorator pattern is used here. By defining all properties in the interface, the child implementation class can choose to enrich the properties which are relevant to it. In the PrintProduct abstract class, only the common properties for all the print products are implemented. A second level abstract class MultiPagePrintProduct is introduced to implement the common properties for all the children of the class, this helps to avoid some code duplication down at the child concrete classes.

In order to handle the creation of these concrete print product classes, the Abstract Factory and Factory Method pattern are used here. These patterns can provide client a unified interface for create those concrete print product. In the actual implementation, the createPrintProduct method will take all the properties required by a PrintProduct, and depends on which particular concrete factory object the client is using, it will only initialize those properties which are valid towards the concrete print product.

An Enumeration PrintProductType is later on introduced. This covers all the current print product types. If customer decide to add new print product type, for instance, map, the changes need to do is just introduce a new print product type, a new concrete print product class and a new factory class associated with it. The print product interface (abstract class PrintProduct) will not be changed very often as explained earlier (machine limitation, employee skill sets etc.), if there is a change for the interface, it is also a sign that there is a couple more other things might be affected. In that situation, reworking on the interface is a much better idea.

An argument was raised when I was working on this design; it is whether the print product interface should be considered as too "fat". A notice here is for simple print product such as business card, it has to carry a lot of extra properties when it is used with this interface. In the actual implementation, it is possible for client to use a property which does not belong to business card. Different from the first design attempt, which basically code up a no-op function for such properties, in the new design an unsupported operation exception has been introduced to couple with this problem. I think a trade off has to be made here for using a uniformed print product interface.

As the result of this “fat” interface, the creation of each concrete print product object also needs to fill a lot of parameters in order to initialize a concrete print product properly. The decision for this version of the design is introduce "fat" constructors and only initialize appropriate properties by each individual concrete factory object. An alternative of this is to only initialize the common properties for all the current products, then ask client code to initialize the other necessary properties for a field. The danger for this approach is that assumption of client fully initialize a concrete product object properly has to be made, which might not always be the case. The Facade pattern might be applied here to guide/organize all the product creation, but there still need a way to pass in those required parameters at some stage. Since there isn’t a clear win of this approach, I stayed with the existing design.

Used Design Patterns
Applied Design Principles
Violdated Design Principles

Print Job and Print Job Workflow

Figure 2: Print Job Overview

As you might guessed already, the print company has a job queue which records all the jobs in the company. These set ups are modelled as class PrintJob and JobQueue. For each print job they had, there would be a number of print product associated with it. An ArrayList is used to store the products for a job in the implementation, the Iterator is used to iterator through the print products list.

For each job, it also has a state field to record which stage of the job is in currently. Typical stages here are quote, design, press (printing), finishing and dispatch. Since there is a requirement to calculate the cost for these states, and the calculation algorithm for each state is different, the State pattern is used here. Another benefit with applying the State pattern here is it also leaves the possibility for adding new state / drop existing state as the company’s business procedure evolves. The state transition for a job is handled by JobStateHandler interface. Currently, there are two state transition patterns existed for the company, one is for jobs which require external designer to do the design stage, another is for normal print jobs. The state transition is also seen as a frequent change candidate, so the Strategy pattern is used here. A JobStateHandler is bind to the job itself, and the concrete handler for each job object will direct the job to follow the right state transition path.

One unsolved problem with this part of the design is the code duplication for get quote price in QuoteState and cost method for other state classes. In theory, the quote should be close to the sum of actual costs which will occur later in each state. Currently, the same algorithm is shared between quote state and other states, as the result, the code duplication occurs. Some other design tricks might be used here for improving this, but I do notice a fact that in the finished system, the quote calculation might not have the same access to a large number of fields which other production state could access. Furthermore, it is wise to say we do not want to use the exactly same algorithm for calculating the quote and the cost for each stage. The cost for each stage is aimed at more accurate actual production cost, and the algorithm for quote should not require a lot of detailed information.

Used Design Patterns
Applied Design Principles
Violdated Design Principles


Print Company Structure

Figure 3: Print Company Structure

As any typical company, the print company consist of a number of employees, departments, customers and in this case external contractors. A Person class is introduced to handle some of the common parts between employees and external contractors. The person class is also used for contactor person in Customer class. The design of the Person class here is more about reduce code duplication rather than providing a common interface, hence Person class is a concrete class in the actual implementation.

As mentioned earlier, there is a JobQueue in the company to hold all the jobs it has. A number of jobs are stored in there. The actual implementation for this job queue is done with ArrayList, and Iterator is used here again. Departments and external contractors need to watch this job queue closely all the time. The Observer pattern is used here with JobQueue as subject, Department and ExternalContractor are used as the observer. Every time job queue changes, departments and external contractors will be noticed and they can re-fetch a job queue from the company. As this system now is still in development stage, the performance hasn’t been a problem for frequent job queue changes. Based on the knowledge of customer, there will be no frequent job queue changes at this stage, but it would be a potential problem in future if the work load for this application increased sharply. The alternative approach for this is to set up a timer and refresh job queue by a pre-set time frequency. This design will lose the real time watching function for the application so the original design is used, but this part of the design still need to be watched closely if there is a performance problem in future.

For security reasons, we do not want external contractor to see the same job queue as departments could do. However, there is also no need for maintaining a different or sub job queue for this purpose alone. The Proxy pattern is used (access control proxy) here to control the access for departments and external contractors. As a result, external contractor will not be able to invoke the getQueue method aimed at internal employees.

Lastly, we only need one instance of print company, which is the owner object for everything else in the application, so the Singleton pattern is used here. The Singleton is not directly applied to JobQueue since the implementation ensures print company will initialize the unique job queue and other object will get the job queue through the print company.

Used Design Patterns
Applied Design Principles
Violdated Design Principles
  • Avoid concrete base class The Person class is a concrete base class for Employee and ExternalContractor.
  • Law of demeter JobQeueu is retrieved from PrintCompany when used by client classes. This is used for ensuring the uniqueness of the JobQueue in the application without using the Singleton pattern for both PrintCompany and JobQueue.


Dropped the Composite Pattern Used by the First Attempt

Figure 4: Old Design (First Attempt, Dropped)

In the first attempt, the Composite pattern was used for the print product family. The reason for using it at that time is for given a consistent interface for client code to use, i.e. define the interface with PrintProduct abstract class. Later analysis found that what it is really needed is actually a Decorator pattern. This is provided as we had the PrintProduct interface already. The actual print product object only provides more behaviours to the defined functionality in the interface. A more direct reason for dropping the Composite design is due to the design I had did not conforms to a part and component relationship, furthermore, the composition brought in by Composite (component node) does not bring more benefit to the application, for keeping things simple, the Decorator is used here.

Implementation Notes

Different from the original vba code based application, the design is coded in Java 1.5. Generic is not used for the final submission due to a UML tool limitation. Some of the interesting topic encountered during the development are organized below.

Thread Safe Singleton Creation

A thread safe getInstance() method for Singleton pattern used with PrintCompany class is applied in the implementation. An interesting read can be found from

http://www-128.ibm.com/developerworks/java/library/j-dcl.html

Source Code

Please see the attached zip file for the source. Media:PrintProduction.zip

Figure 5: Print Product Overview

Future Work

As this project is still evolving, more work on the design might be added. The next big task for this project is to design the data access layer strcuture. As most of the typical business applications, database interaction is one of the core part of the application. I will keep working on this over next month. In the meanwhile, I will seeking for better solution for the duplicate code problem this application had with the quote calculation.

Personal tools