The Collection Switch Design Pattern

The Collection Switch Design Pattern: The elimination of
lengthy conditional statements using collections of
objects that implement a common interface and dynamic
class loading.
John E. Gresh
maintenance of the collection used to replace the lengthy
conditional represents a substantial amount of effort [7].
ABSTRACT
A design pattern for the elimination of lengthy conditional
statements named the Collection Switch is presented. The design
pattern presented will provide software developers a powerful
tool to argue against the implementation of systems that do not
scale well as a consequence of the need to maintain conditional
mappings such as lengthy if-then-else statements, hash maps,
XML representations of conditional logic, etc.
The design pattern presented uses a collection of objects that
implement a common interface and dynamic class loading to
replace lengthy conditional logic. A formal methodology is
presented and applied to demonstrate that using the Collection
Switch pattern saves costs incurred through the use of traditional
implementations found in the literature such as Factory Patterns,
Model View Controller Servlets, and various other Controller
mechanisms.
Keywords
Collection Switch, Conditional, Case, Switch, if-then-else, Object
Oriented Design, Design Pattern, Factory, Controller, MVC,
Servlet.
1. INTRODUCTION
Frameworks and design methodologies that promote the use of
lengthy conditional statements continue to appear regularly in the
professional and academic literature. These conditional statements
can take many forms including traditional in line coding (e.g. ifthen-else and other conditional statements) [1,2,5,14,16,26],
collections of objects or object references [6,7,9,21], definition of
conditional
logic
in
external
files
(e.g.
XML)
[4,8,10,11,17,18,19,24,28], or the persistence of the conditional
logic in external persistent stores (e.g. databases) [27].
Previous publications have suggested the use of collections of
classes to replace lengthy conditionals [7,13]. However, these
publications do not provide a formal demonstration that the
proposed solution is an improvement over existing solutions and
these publications do not suggest the use of dynamic class loading
[20] to eliminate the need of the software developer to maintain
the collection. Previous work does support the assertion that the
In [12], Fowler suggests the use of dynamic class loading to
implement a portion of the conditional logic required for a
controller class in a web application but does not include request
forwarding as part of the functionality provided by the
dynamically loaded class. Instead request forwarding is hard
coded in an inline conditional statement that requires modification
in the controller classes. This modification can be eliminated
through the use of dynamic class loading as will be demonstrated
below.
In [25] Rupp suggests MVC is not an adequate solution for
implementation of Controller logic for scalable J2EE web
applications. However, Rupp does not provided details regarding
how an improved solution can be implemented and does not
demonstrate that the methodology proposed represents an
improvement over current best practices.
The pattern presented here (see Figure 1 for a generalized
implementation in Java) will be demonstrated to represent an
improvement over current standard design practices by comparing
the methodology proposed to one current standard practice for the
implementation of a Factory [15] and current standard practice for
the implementation of a Controller [16]. The results of this
comparison will then be generalized to other methodologies
presented in the literature [3,6,8,12,17].
The following three null hypotheses will be tested to demonstrate
the improvement over existing methodologies.
1.
It can be demonstrated that all errors that can occur
in a system that uses lengthy conditional
statements can occur in a system that uses a
collection of objects that implement a common
interface to perform the same task.
2.
There is no demonstrable difference in the number
of lines of code that need to be modified to extend a
system that uses lengthy conditional statements
and the number of lines of code that need to be
modified to extend a system that uses a collection
21st Computer Science Seminar
SD3-T3-1
3.
of objects that implement a common interface to
perform the same task.
2. METHODOLOGY
2.1 System Design
It can be demonstrated that a system that uses
lengthy conditional statements demonstrates reuse
in all cases where a system that uses a collection of
objects that implement a common interface to
perform the same task demonstrates reuse.
The value of the Collection Switch design pattern was first tested
by comparing a traditional implementation of a Factory pattern
[15] with an implementation of the Factory pattern that uses the
Collection Switch design pattern.
/* Client definition */
public class Client {
private String packageName ="edu.rh.collectionSwitch";
public void useCollectionSwitchFactory()
throws Exception {
Factory factory = new Factory();
Interface instance;
instance = factory.getInstance(
packageName
+ "." + "Implementation_01");
instance.executeCommand();
instance = factory.getInstance(
packageName
+ "." + "Implementation_02");
instance.executeCommand();
}
/* Factory definition */
public class Factory {
public Interface getInstance(String specification)
throws Exception {
return (Interface)
Class.forName(specification).newInstance();
}
}
/* Interface definition */
public interface Interface {
public void executeCommand();
}
/* Implementation 1 definition */
public class Implementation_1
implements Interface {
public void executeCommand() {
System.out.println("impl 01");
}
}
/* Implementation 2 definition */
public class Implementation_2
implements Interface {
public void executeCommand() {
System.out.println("impl 02");
}
}
Figure 1. Source code for a generalized implementation of
the Collection Switch pattern implemented in Java.
Both systems were designed to generate an instance of an Animal
interface based upon a client request for an animal of a given type
via a String. Both systems were initially created with six
implementations of Animal: Rat, Ox, Tiger, Rabbit, Ram, and
Rooster. Both systems used the same source code for the Animal
interface and the six initial implementations of Animal. Each
Factory class was created with a method with the signature public
Animal getAnimal(String name). In each factory class the
implementation of getAnimal returned one of the six different
types of Animal objects Ox, Rabbit, Ram, Rat, Rooster, and Tiger
where name is given as Ox, Rabbit, Ram, Rat, Rooster, and Tiger
respectively. Each of the systems was created to throw an
exception if the String provided by the client was not one of the
Strings listed above.
Each Factory implementation was implemented via a method with
the signature public Animal[] getAllAnimals(). In each case the
getAllAnimals method was created to return an array of Animal
objects that contains one and only one of each of the six animals
available.
Six additional Animal implementations were then added to each
system: Dragon, Snake, Horse, Monkey, Dog, and Pig.
Modifications were then made to each of the systems so that
getAnimal returns one of the twelve different types and so that
getAllAnimals returns an array of Animals that contains one and
only one instance of each of the twelve animal types available.
The value of the Collection Switch design pattern was then tested
by comparing an implementation of a MVC Servlet based web
application using code described by Hall and Brown [16] and an
implementation using a MVC Servlet based web application using
the Collection Switch design pattern. The chosen application was
a variation of the Animal system described above.
Both of the above systems were originally required to process
requests for six different operation parameters by forwarding the
client to a JSP depending upon the value given for the operation
variable. The above two systems were then modified to forward a
user to one of twelve unique web pages for each of the operation
parameters.
2.2 Implementations
Implementation of a Factory and Controller using current standard
practices led to code that required modification to extend the
systems to produce additional types of objects and to perform
additional actions respectively.
It can be seen from Figure 2 that each new implementation of
Animal provided by the factory requires an additional conditional
statement. It can be seen from Figure 3 that no such changes are
21st Computer Science Seminar
SD3-T3-2
required for the Collection Switch implementation of the factory.
Likewise, it can be seen from Figure 4 that each new action
performed by the Controller Servlet implemented using traditional
methodologies requires modification for new actions. It can be
seen from Figure 5 that no such modifications are required for the
Controller Servlet implemented using the Collection Switch
pattern.
public class AnimalFactory {
public Animal getAnimal(String name)
throws Exception {
if ("Ox".equals(name)) {
return new Ox();
} else if ("Rabbit".equals(name)) {
return new Rabbit();
} else if ("Ram".equals(name)) {
return new Ram();
} else if ("Rat".equals(name)) {
return new Rat();
} else if ("Rooster".equals(name)) {
return new Rooster();
} else if ("Tiger".equals(name)) {
return new Tiger();
} else if ("Dragon".equals(name)) {
return new Dragon();
} else if ("Snake".equals(name)) {
return new Snake();
} else if ("Horse".equals(name)) {
return new Horse();
} else if ("Monkey".equals(name)) {
return new Monkey();
} else if ("Dog".equals(name)) {
return new Dog();
} else if ("Pig".equals(name)) {
return new Pig();
}
throw new Exception
("No animal defined for " + name);
}
public Animal[] getAllAnimals() throws Exception {
//size of array needs to change for new animals
Animal[] animals = new Animal[12];
//items need to be added for new animals
animals[0] = getAnimal("Ox");
animals[1] = getAnimal("Rabbit");
animals[2] = getAnimal("Ram");
animals[3] = getAnimal("Rat");
animals[4] = getAnimal("Rooster");
animals[5] = getAnimal("Tiger");
animals[6] = getAnimal("Dragon");
animals[7] = getAnimal("Snake");
animals[8] = getAnimal("Horse");
animals[9] = getAnimal("Monkey");
animals[10] = getAnimal("Dog");
animals[11] = getAnimal("Pig");
//return array to client
return animals;
}
}
Figure 2. Animal Factory implementation after the system
was extended by the addition of six new implementations of
Animal.
public class AnimalFactory {
public static final String
ANIMAL_PACKAGE_NAME =
"edu.rh.collectionSwitch.animals";
public Animal getAnimal(String name)
throws Exception {
String fullName =
ANIMAL_PACKAGE_NAME
+ "." + name;
return (Animal)
Class.forName(fullName).newInstance();
}
public Animal[] getAllAnimals()
throws Exception {
String animalSourceDirectory =
URLDecoder.decode
(getClass().getResource("../../animals").getFile());
File animalClassSource =
new File(animalSourceDirectory);
File[] files = animalClassSource.listFiles();
Animal[] animals = new Animal[files.length];
for (int i = 0; i < files.length; i++) {
String fileName = (files[i].getName());
String className =
fileName.substring(0, fileName.indexOf("."));
animals[i] = getAnimal(className);
}
return animals;
}
}
Figure 3. Collection Switch Animal Factory implementation
before and after the new implementations of Animal.
public class Controller {
public void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String operation =
request.getParameter("operation");
if (operation == null) {
operation = "unknown";
21st Computer Science Seminar
SD3-T3-3
}
String address;
if (operation.equals("Ox")) {
address = "/WEB-INF/Ox.jsp";
} else if (operation.equals("Rabbit")) {
address = "/WEB-INF/Rabbit.jsp";
} else if (operation.equals("Ram")) {
address = "/WEB-INF/Ram.jsp";
} else if (operation.equals("Rat")) {
address = "/WEB-INF/Rat.jsp";
} else if (operation.equals("Rooster")) {
address = "/WEB-INF/Rooster.jsp";
} else if (operation.equals("Tiger")) {
address = "/WEB-INF/Tiger.jsp";
} else if (operation.equals("Dragon")) {
address = "/WEB-INF/Dragon.jsp";
} else if (operation.equals("Snake")) {
address = "/WEB-INF/Snake.jsp";
} else if (operation.equals("Horse")) {
address = "/WEB-INF/Horse.jsp";
} else if (operation.equals("Monkey")) {
address = "/WEB-INF/Monkey.jsp";
} else if (operation.equals("Dog")) {
address = "/WEB-INF/Dog.jsp";
} else if (operation.equals("Pig")) {
address = "/WEB-INF/Pig.jsp";
} else {
throw new ServletException(address + " unknown");
}
RequestDispatcher dispatcher =
request.getRequestDispatcher(address);
dispatcher.forward(request, response);
}
}
Figure 4. Modified Controller class for the Controller
implementation as described by [16].
public class Controller extends HttpServlet {
private String mActionName = "actionName";
private String mPrefix = "";
private String mPostFix = "";
protected String getActionName() {
return mActionName;
}
protected void setActionName(String actionName) {
mActionName = actionName;
}
protected String getPrefix() {
return mPrefix;
}
protected void setPrefix(String prefix) {
mPrefix = prefix;
}
protected String getPostfix() {
return mPostFix;
}
protected void setPostfix(String postfix) {
mPostFix = postfix;
}
public void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
public void doPost(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected void processRequest(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
ActionInterface action = null;
String actionName = mPrefix
+ request.getParameter(mActionName)
+ mPostFix;
try {
action = (ActionInterface)
Class.forName(actionName).newInstance();
action.processRequest(request, response);
RequestDispatcher disp =
request.getRequestDispatcher(action.getNextUrl());
disp.forward(request, response);
} catch (Throwable t) {
throw new ServletException(t);
}
}
}
public interface ActionInterface {
public void processRequest(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
public String getNextUrl();
}
Figure 5. Controller class for the Collection Switch
Controller implementation and its ActionInterface before
and after modifications to requirements.
21st Computer Science Seminar
SD3-T3-4
3. RESULTS
3.1 Comparison of Implementations
Use of the Collection Switch design pattern in an implementation
of the Factory pattern allows for the creation of a Factory class
that can be extended to provide clients with additional
implementations without any change to the Factory class. In the
example provided above an AnimalFactory was created to produce
instances of Dragon, Snake, Horse, Monkey, Dog, and Pig. The
system was then expanded to also provide instances of Ox,
Rabbit, Ram, Rat, Rooster, and Tiger. This was accomplished
with no modifications to the factory class used.
As no changes are made to the factory class to extend the
implementations provided by the factory, errors cannot be
introduced into the factory class by such additions.
Therefore, the only errors that can be introduced to the Animal
Collection Switch system are those introduced by the addition of
the new implementations of Animal, i.e. the classes representing
Dragon, Snake, Horse, Monkey, Dog, and Pig. The potential for
these errors also exists in the traditional Animal Factory system as
the same classes also need to be introduced to that. The addition
of new classes are equivalent operations for the traditional Factory
pattern and the Collection Switch pattern, therefore the potential
for error for this operation is identical. These errors include the
replacement of a working class with a class that is in error, the
introduction of a new class that is in error, and the introduction of
a class that cannot be instantiated (i.e. a class with an error in the
constructor).
The addition of new implementations provided by the Factory
using a traditional factory pattern requires modification of the
Factory class. These modifications could introduce errors and
these errors can affect all clients of the Factory.
Therefore, the first null hypothesis that all errors that can occur in
a system that uses lengthy conditional statements can also occur
in the Collection Switch pattern is shown to be false.
In the Animal Collection Switch Factory example above the
system is extended to include Ox, Rabbit, Ram, Rat, Rooster, and
Tiger. This is done by simply placing the new classes in the class
path of the system. No modification to the existing source code is
made. Using the traditional factory pattern in the Animal Factory
the Factory class is modified to provide the new instances of
Animal (see Figure 2).
Therefore, the second null hypothesis that there is no
demonstrable difference in the number of lines of code that need to
be modified to extend a system using the two approaches is
shown to be false. The Collection Switch pattern eliminates the
growth of the Factory implementation seen in traditional Factory
patterns.
The Factory implemented in the example above using the
Collection Switch pattern does not allow for much reuse. This
factory is of little use to any system that does not need Animal
instances created. This could be remedied through the use of
generics as was done for the Product Trader system [Baumer and
Riehl, 7]. Therefore this example in its current form does not
directly address the third null hypothesis. Hence we turn our
attention to the Controller example.
The traditional controller class used in the example presented here
required modifications for the addition of new actions. Each new
action required the addition of a new conditional to test for that
action.
The controller class used in the Collection Switch Controller
example presented in this paper could be used as a controller class
in any number of other web applications without modification.
This is clearly not the case with the Controller class implemented
using more traditional methods defined in the literature.
Therefore, the third null hypothesis that asserts no improvement
in the level of reuse in the Collection Switch approach is shown to
be false. The Collection Switch pattern demonstrates reuse in the
case of the Controller class above where the Controller class
implemented using methods defined in the literature does not.
3.2 Alternatives
Alternative implementations of MVC Controller classes described
in the literature will now be considered and compared to the
Collection Switch Controller implementation introduced here.
First, Jakarta Struts [3] must be considered. At the time of this
writing Struts is arguably a contender for the gold standard for the
implementation of J2EE web applications. It has been described
as "the de facto framework for building J2EE web applications
structure according to the MVC architectural pattern," [8] "A
technology that no Web programmer can afford to ignore," [17],
etc.
Struts (version 1.2) uses one or more XML configuration files to
determine what action to take for a given request to the Controller
[17]. Hypothetically, This approach does not solve the problem
of eliminating the growth of the lengthy conditional as the size of
the application grows. The XML file or files representing the
lengthy conditional statement will grow as the number of actions
used by the system grows. Therefore, in theory, Struts incurs the
costs of increased potential for error, increase in size, and limited
reuse that have been demonstrated here to be absent with a
controller implemented using the Collection Switch design pattern.
Hypothetically, the potential for error is exacerbated by the
ability to create mappings that point to other mappings, i.e. to
chain mappings together. When a series of mappings are chained,
any incorrect mapping in the chain will cause an unexpected or
undesired outcome. Any incorrect mapping in the chain will cause
an error. Therefore, the longer the chain the greater the potential
for errors. The length of the mapping chain is reduced to 0
through the use of dynamic class loading in the Collection Switch
implementation of a controller class. Thereby, any error in
mapping is eliminated (with the obvious caveat that the original
class name requested by the client must be valid).
21st Computer Science Seminar
SD3-T3-5
Similar to Struts, Sun's "Pet Store" implementation uses an XML
file to define controller action mappings [4]. Hypothetically, this
implementation incurs the costs of increased potential for error,
increase in size and limited reuse that have been demonstrated here
to be absent with a controller implemented using the Collection
Switch design pattern.
Encapsulation of mapping has been suggested in the literature by
Alure, Crupi, and Malks [6]. They suggest mappings can take
two forms. One, the mapping can be direct whereby "the actual
target object is held within the Map and can be directly retrieved."
Two, the mapping can be indirect whereby "an indirect handle
describes the scenario where the Map contains an object that
refers to the ultimate target indirectly." These authors do not
suggest the use of dynamic class loading to minimize the cost of
this mapping. These authors do not demonstrate a controller
implementation that is free from the costs of increased potential
for error, increase in size and limited reuse. All these costs have
been demonstrated here to be absent with a controller
implemented using the Collection Switch design pattern.
The use of dynamic class loading if a JSP is used as a controller
has been suggested in the literature by Fowler [12]. Fowler
suggests the use of dynamic class loading to add an attribute to the
page context of a JSP but the approach shown does not define all
navigation logic and thereby does not eliminate the need to modify
the JSP with the addition of new navigation requirements such as
those investigated here. The code presented by Fowler is not as
loosely coupled as it could be and is not as loosely coupled as the
code presented in the Collection Switch pattern. The Servlet
implementation that is provided by Fowler in [12] uses a mapping
class to encapsulate mappings from the controller class. How this
mapping class should be implemented is not provided.
[3] "The Apache Foundation: Struts", Available at HTTP:
http://struts.apache.org
[4] "Java Pet Store", Available at HTTP:
http://java.sun.com/developer/releases/petstore
[5] "Java Education and Learning Community: Abstract
Factory", Available at HTTP:
http://ww.javapractices.com/Topic128.cjp
[6] Alur, D., Crupi, J., and Malks, D., Core J2EE Patterns, Best
practices and Design Strategies, 2nd. ed., Palo Alto,
California, Sun Microsystems, 2003.
[7] Baumer, D, and Riehle, D., "Product Trader," in Pattern
Languages of Program Design 3, R.C. Martin, D. Riehle,
and F. Buschmann, Eds. Reading MA: Addison-Wesley,
1997. Chapter 3.
[8] Bellas, F., Fernandez, D., and Muino, A., A flexible
framework for engineering 'my' portals, Proceedings of the
13th international conference on World Wide Web, pp. 234243, 2004.
[9] Burbeck, S. Applications Programming in Smalltalk-80(TM):
How to use Model-View-Controller (MVC), Available at
HTTP: http://www.cs.uiuc.edu/users/smarch/stdocs/mvc.html, 1987, revised 1992.
[10] Chun, L. G., Yanhua, W., and Hanhong, L. X., A Novel Web
Application Frame Developed by MVC, ACM SIGSOFT,
2003.
[11] Corwin, J., Bacon, D. F., Grove, D., and Murthy, C., MJ: A
Rational Module System for Java and its Applications, ACM
SIGPLAN Notices, vol. 38, no. 11, Oct., 2003.
[12] Fowler, M., Patterns of Enterprise Application Architecture,
Boston, Addison-Wesley, 2003.
[13] Fowler, M., Refactoring: improving the design of existing
code, Reading MA: Addison-Wesley, 1999.
4. CONCLUSIONS
This paper presented a novel, previously undefined, design
pattern: The Collection Switch.
Use of the Collection Switch pattern eliminates any representation
of a lengthy conditional created and maintained by the authors of a
system. The Collection Switch pattern defers this responsibility
to the underlying language by using dynamic class loading and
thereby reduces the number of potential errors that can be
generated, reduces the amount that the system will grow, and adds
additional opportunities for reuse.
5. REFERENCES
[1] "The Java Boutique: Java Tutorial: A very simple JSParchitecture", Available at HTTP:
http://javaboutique.internet.com/tutorials/Simple_JSP/control
ler.html.
[2] "JSP Templates: Model-View-Controller for Servlets",
Available at HTTP:
http://www.caucho.com/articles/jsp_templates.xtp.
[14] Grand, M., Patterns in Java, Volume 1, New York, John
Wiley & Sons, 1998.
[15] Gamma, E., Helm, R., Johnson, R., and Vlissides, J., Design
Patterns: elements of reusable object-oriented software,
Boston: Addison-Wesley, 1994.
[16] Hall, M., and Brown, L., Core Servlets and JavaServer
Pages Volume 1: Core Technologies, Upper Saddle River,
NJ: Prentice Hall, 2004.
[17] Holmes, J., Struts: the complete reference, H. Schildt, Ed.,
New York: McGraw-Hill, 2004.
[18] Kassem, N., Designing Enterprise Applications with the J2EE
Platform, Second Edition, Addison-Wesley, Boston, 2000.
[19] Kojarski, S., and Lorenz, D. H., Domain Driven Web
Development With WebJinn, OOPSLA, 2003.
21st Computer Science Seminar
SD3-T3-6
[20] Liang, S., and Bracha, G., Dynamic Class Loading in the Java
Virtual Machine, ACM SIGPLAN Notices, vol. 33, no. 10,
1998.
[25] Rupp, N. A., Beyond MVC: A New Look at the Servlet
Infrastructure, Available at HTTP:
http://today.java.net/lpt/a/62, 2003.
[21] Nguyen, D., and Wong, S. B., Design Patterns for Games,
SIGCSE, 2002.
[26] Seshadri, G., Understanding JavaServer Pages Model 2
architecture, Available at HTTP:
http://www.javaworld.com/javaworld/jw-12-1999/sw-12-ssjjspmvc_p.html, 1999.
[22] Reenskaug, T., Models-Views-Controllers, Available at
HTTP: http://heim.ifi.uio.no/~trygver/themes/mcv/mvcindex.html, 1979.
[23] Reenskaug, T., The Model-View-Controller (MVC) Its Past
and Present, Available at HTTP:
http://heim.ifi.uio.no/~trygver/themes/mcv/mvc-index.html,
2003.
[24] Searns, B., Murray, G., Singh, I., et. al., Enterprise
Applications with the J2EE Platform, Second Edition,
Available at HTTP:
http://java.sun.com/blueprints/guidelines/designing_enterprise
_applications_2e/web-tier/web-tier5.html
[27] Yoder, J. W., Balaguer, F., and Johnson, R., Architecture and
Design of Adaptive Object-Models, ACM SIGPLAN Notices,
vol. 36, no. 12, Dec., pp. 50-60, 2001.
[28] Zhang, J., Chung, J., and Chang, C. K., Towards Increasing
Web Application Productivity, in Proceedeings of the 2004
ACM symposium on Applied computing, pp. 1677-1681,
2004.
21st Computer Science Seminar
SD3-T3-7