Answers to Design Pattern Questions

Abstract Factory | Adapter | Composite | Decorator | Facade | Flyweight | Factory Method | Prototype | Proxy | Singleton | Strategy | Template Method

Factory Method

  • How does this promote loosely coupled code?
    The factory provides a centralized place to put decision code for selecting between sub classed objects.  This means that to add another sub classed object the only work is in creating the new object and adding a few lines of decision code to the factory.  This is especially  great in highly modularized systems, in which, modules may be added and removed from the system at any point.

Abstract Factory

  • In the Implementation section of this pattern, the authors discuss the idea of defining extensible factories. Since an Abstract Factory is composed of Factory Methods, and each Factory Method has only one signature, does this mean that the Factory Method can only create an object in one way?
    In the normal design of an abstract factory this is the case, however, it would be possible to pass a parameter to a factory method and return one of many sub classed objects based on that parameter. 
     
  • Consider the MazeFactory example. The MazeFactory contains a method called MakeRoom, which takes as a parameter one integer, representing a room number. What happens if you would also like to specify the room's color & size? Would this mean that you would need to create a new Factory Method for your MazeFactory, allowing you to pass in room number, color and size to a second MakeRoom method?
    This is definitely one possibility.  Another would be to modify the existing MakeRoom method with default values for color & size.  However, these may not provide the desired flexibility.  See below for more ideas.
     
  • Of course, nothing would prevent you from setting the color and size of the Room object after it has been instantiated, but this could also clutter your code, especially if you are creating and configuring many objects. How could you retain the MazeFactory and keep only one MakeRoom method but also accommodate different numbers of parameters used by MakeRoom to both create and configure Room objects?
    One way to handle this would be to create a single MakeRoom that takes two parameters.  The first parameter is the room number since that seems to be an absolutely required and another that is just a list of zero or more key / value pairs that MakeRoom uses to determine other room settings such as size and color.

Composite

  1. How does the Composite pattern help to consolidate system-wide conditional logic?
    The Composite pattern makes leaf and composite objects look the same to the client.  This keeps the client from having to identify the object before it uses it.  The result is a centralized design that is much easier to maintain when the design changes.
     
  2. Would you use the composite pattern if you did not have a part-whole hierarchy? In other words, if only a few objects have children and almost everything else in your collection is a leaf (a leaf that has no children), would you still use the composite pattern to model these objects?
    This design pattern would certainly be a candidate for use in this case.  Even though most of the objects are leaves, those leaves can be part referenced and organized by a composite object.  In fact, this is the way most composite designs are implemented, with one composite object grouping multiple types of leaf objects.

Proxy

  • If a Proxy is used to instantiate an object only when it is absolutely needed, does the Proxy simplify code?
    Proxy doesn't necessarily simplify code.  The Proxy is used to create an object when needed, allowing the application to run up until this point unimpeded by the burden of loading the proxy object, which likely encapsulates large amounts of data or an action that will take a long period of time to execute.

Prototype

  1. When should this creational pattern be used over the other creational patterns?
    The Prototype should be used when multiple similar objects are needed that differ only in the state of their internal data.  This allows for creating complex objects, saving them, and reusing them.  Moreover, multiple complex objects can be created and saved from the base object.
     
  2. Explain the difference between deep vs. shallow copy.
    A deep copy, copies the instance variables of the cloned object into the prototype.  The shallow copy just copies references to the instance variables, allowing the two object to share the variables.

Singleton

  • The Singleton pattern is often paired with the Abstract Factory pattern. What other creational or non-creational patterns would you use with the Singleton pattern?
    Factory - The factory just provides the logic for creating other objects.  It would make sense to only have one around if for no other reason than to conserve memory.
    Adapter - When the Adapter wraps a shared resource, an Adapter Singleton can be used to ensure that everyone is using that resource properly.
    Builder - Similar to Adapter there may be a shared resource that the Builder uses and it needs to manage accesses to that resource.

Decorator

  • In the Implementation section of the Decorator Pattern, the authors write: A decorator object's interface must conform to the interface of the component it decorates. Now consider an object A, that is decorated with an object B. Since object B "decorates" object A, object B shares an interface with object A. If some client is then passed an instance of this decorated object, and that method attempts to call a method in B that is not part of A's interface, does this mean that the object is no longer a Decorator, in the strict sense of the pattern? Furthermore, why is it important that a decorator object's interface conforms to the interface of the component it decorates?
    Object B is still a Decorator, in fact, this is the whole purpose of the Decorator.  Object B is providing additional functionality on top of the object it decorates.  The ScrollDecorator and BorderDecorator examples in the book exhibit this quite well.  The ScrollDecorator provides a ScrollTo method and the BorderDecorator provides a DrawBorder method.  Plus, both provide a Draw method.  The Draw method is the shared interface while the others provide the additional functionality. 
    The shared interface is important because it provides transparency to the client which shouldn't notice if the Decorator isn't there.

Flyweight

  1. What is a non-GUI example of a flyweight?
    In a Voting System there would be hundreds of BallotItem Objects, of which each Voter needs some subset.  However, for each Voter the only unique information is the result of the Voter's Vote.  Thus, a Flyweight could be used to provide access to the BallotItems without creating new ones for each Voter.
     
  2. What is the minimum configuration for using flyweight? Do you need to be working with thousands of objects, hundreds, tens?
    There is no set limit.  If only two very large objects were needed in the system and they differed very little, the Flyweight would be perfect for aggregating their similarities and providing access to different data for each.  The Flyweight is even more useful with large numbers of similar objects as it vastly reduces the memory usage of the program. 

Facade

  1. How complex must a sub-system be in order to justify using a facade?
    The sub-system does not have to be very complex.  The Facade can be used to provide a simplified interface to the underlying sub-system or perhaps a small subset of the sub-system.  Facades definitely earn their keep in large, cumbersome subsystems, but they can provide bountiful advantages to even small systems.
     
  2. What are the additional uses of a facade with respect to an organization of designers and developers with varying abilities? What are the political ramifications?
    The Facade is best at hiding the gory details of complex subsystems.  An organization can use this to its advantage by hiring highly skilled developers to build a "dumbed-down" Facade for the lesser skilled developers to use.  This can make for rapid development, makes for a good design, and makes good economic sense (i.e. not everyone is a high-priced expert).  However, this can lead to a "we're better than they are" environment, which leads to poor morale.  Poor morale is one of the biggest killers for any development effort.

Adapter

  • Would you ever create an Adapter that has the same interface as the object which it adapts? Would your Adapter then be a Proxy?
    Creating an Adapter that has the same interface would be perfectly acceptable.  This would allow for the flexibility of changing out the adapted object at any time.  The interface would still be the same for the rest of the application, but the new adapter allows the new object to work just like the old one.  Moreover, the "same interface" may be a well known or well documented interface to a given object.  The developers may be very accustomed to developing to this interface.  However, a new object/technology comes along and the Adapter provides the same interface as has always been there. 
    This could be considered a Proxy, but Proxies are usually used to hold the place of an object until is needed at execution time and then the Proxy loads the needed data / objects. 

Strategy

  1. What happens when a system has an explosion of strategy objects? Is there some better way to manage these strategies?
    The best way to handle this is to remove all state from the strategies and turn them into Flyweights or Singletons. The Flyweight would work if there was some small amount of state that the Strategy needed to maintain. However, if there is no state and the Strategy just does processing, then a Singleton would suffice.
     
  2. In the implementation section of this pattern, the authors describe two ways in which a strategy can get the information it needs to do its job. One way describes how a strategy object could get passed a reference to the context object, thereby giving it access to context data. But is it possible that the data required by the strategy will not be available from the context's interface? How could you remedy this potential problem?
    One way that the book lays out is to just pass in all the data that the context has to the Strategy. However, this has the problem of possibly feeding more data than necessary to the Strategy, plus it may be an inefficient method of getting the data to the Strategy. Another way is to make the Context a Template that takes Strategies as parameters. This gives the Strategy finer grained access to the inner workings of the Context.

Template Method

  • The Template Method relies on inheritance. Would it be possible to get the same functionality of a Template Method, using object composition? What would some of the tradeoffs be?
    Yes object composition could be used to implement the Template Method. Both rely on child classes to perform key operations. However, the Composite is designed to build objects up out of primitive objects and other Composite objects, which points out the key difference between the two. The Template is designed to handle abstracted algorithms or actions while the composite is designed to build up more complex objects. Using the Composite for the Template Method may be confusing to the implementer if the algorithm is not "composed" of many primitive and composite algorithm components.

 

Still To Come

Chain of Responsibility

Memento

Mediator