|
How does this promote
loosely coupled code? |
|
|
Answer |
The abstraction that Factory
Method brings to decide which of the possible classes to return depending on
the data provided to it keeps the data dependence separated from the classes’
useful methods. In addition, the user only needs to be aware of the interface
or methods of the base class, which also provides some level of indirection. With these, factory method
promotes loosely coupled code because users do not need to rewrite or change
the methods according to the change of data provided to a class. It simply
requires changing or adding the derived classes pertinent to the change of
data provided to the class. |
|
1) 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? |
|
|
Answer |
Adding a new kind of product
requires changing the Abstract Factory interface and all the classes that
depend on it. Nevertheless, we may
add a new kind of product by adding a parameter to operations that create
object. The parameter specifies the kind of the object to be created. This
approach is more flexible but less safe than changing the Abstract Factory
interface and all the classes that depend on it. However, it only needs a
single operation with a parameter indicating the kind of object to create. |
|
Abstract Factory |
2) 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? |
|
Answer |
We may create a new Factory Method to pass
in room number, color and size to a second MakeRoom method. But we can add
set method to specify the room’s color and size after the object room is
created or overload MakeRoom method with those additional parameters. |
|
Abstract Factory |
3) Of course, nothing would prevent you from
setting the color and size of the Room object after is 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? |
|
Answer |
Overloading MakeRoom method can be one way
to keep only one method and accommodate different number of parameters though
it may introduce some ambiguities for the user to use it. |
|
Builder |
Like the Abstract Factory pattern, the
Builder pattern requires that you define an interface, which will be used by clients
to create complex objects in pieces. In the MazeBuilder example, there are
BuildMaze(), BuildRoom() and BuildDoor() methods, along with a GetMaze()
method. How does the Builder pattern allow one to add new methods to the
Builder's interface, without having to change each and every sub-class of the
Builder? |
Answer |
We may provide a
default implementation of the new method that we would like to add to the
Builder’s interface so that all the subclass of the Builder inherits the method
and use it. Then the method must be defined as concrete in the Builder class.
However, if one would like to have the newly added method to have specific
algorithm for each subclass, then every subclass has to be changed. |
|
1) When should this
creational pattern be used over the other creational patterns? |
|
|
Answer |
§
When
a system should be independent of how its products are created, composed, and
represented §
When
the classes to instantiate are specified at run-time, for example, by dynamic
loading §
To
avoid building a class hierarchy of factories that parallels the class
hierarchy of products §
When
instances of a class can have one of only a few different combinations of
state. It may be more convenient to install a corresponding number of
prototypes and clone them rather than instantiating the class manually, each
time with the appropriate state. I.e. whenever you need classes that differ
only in the type of processing they offer §
When
creating an instance of a class is very time consuming or complex in some way |
|
Prototype |
2) Explain the
difference between deep vs. shallow copy. |
Answer
|
The difference between
shallow and deep copying is only relevant for compound objects such as objects
that contain other objects, lists or class instances. A shallow copy
constructs a new compound object and then to the extent possible inserts references
into it to the objects found in the original. A deep copy
constructs a new compound object and then, recursively, inserts copies
into it of the objects found in the original. |
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? |
Answer
|
For creational pattern, it could be used with Builder and
Prototype. The internal components that consist of the object could be Singleton
with Builder and Prototype object that is cloned could be Singleton. For non-creational pattern, Façade may be used with
Singleton pattern in case one single instance of interface to a set of
interfaces in the subsystem is needed. Mediator or Proxy can be also paired
with Singleton in the same sense. |
Composite
|
1) How does the Composite
pattern help to consolidate system-wide conditional logic? |
|
Answer |
Composite pattern enables the
client treat both individual objects and compositions of object uniformly by
defining an abstract component class. A client can access those individual
objects and compositions of objects without knowing whether the object is a
leaf or composite. It allows the same conditional logic to be used to handle
both in system wide manner. |
|
Composite |
(ii) 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? |
|
Answer |
It depends on whether we
need to have a common interface to both individual objects and composition of
objects. If it is, composite pattern can be useful to model those objects. In
case that most leaf nodes(individual objects) have some common operation,
defining that operation in a component is also good to provide common
interface. |
Observer
|
1) The classic
Model-View-Controller design is explained in Implementation note #8:
Encapsulating complex update semantics. Would it ever make sense for an
Observer (or View) to talk directly to the Subject (or Model)? |
|
Answer |
The controller ensures
that all observers are notified only once after all subjects have gone
through changes to avoid unnecessary updates of observers in the
implementation note. If an observer needs to reflect the change of the
subject without delay or immediately, then it would make sense for an
observer to talk directly to the Subject. However, this could make the design
unclear and difficult to follow when there are many observers that the
controller does not regulate their interaction with subject (model). |
|
Observer |
2) What are the properties
of a system that uses the Observer pattern extensively? How would you
approach the task of debugging code in such a system? |
|
Answer |
When a system uses the
Observer pattern extensively, it can be roughly divided into observer and
subject part. There would be many communications between them and it could be
very tricky to keep track of to which observers the state change of which
subjects notifies. It may cause debugging the code difficult due to
dependencies between objects. Classifying the
communications between subjects and observers could help debugging the code
in such a system. Because we know what subject causes the change in the
observer, we can check that the change in the observer states is done
correctly and consistent with the change of the subject. |
|
Observer |
3) Is it clear to you how
you would handle concurrency problems with is pattern? Consider an
Unregister() message being sent to a subject, just before the subject sends a
Notify() message to the ChangeManager (or Controller). |
|
Answer |
We can use timestamp on
the Notify() message from a subject to Controller in the order that the
subject send. Then the Controller
keeps the messages from the last consistent state between the subject and
observer in the buffer, updates the observer and checks the states of both
observer and subject. |
Proxy
|
If a Proxy is used to
instantiate an object only when it is absolutely needed, does the Proxy
simplify code? |
|
Answer |
The Proxy pattern introduces
a level of indirection when accessing an object. It does not necessarily mean that Proxy simplifies code because
the real subject of proxy has to be implemented though its instantiation can
be deferred until it is necessary.
Moreover, we have to consider some issues such as how the real subject
must be replaced by the proxy object and how to control access to the real
object in implementation. On the other hand, proxy can simplify the code in
that the remote proxy hides the fact that an object resides in a different
space and both protection proxies and smart reference allow additional
housekeeping tasks when an object is accessed because we do not need to take
care of those restrictions in the real subject code. |
Strategy
|
1) What happens when a
system has an explosion of strategy objects? Is there some better way to
manage these strategies? |
|
Answer |
In case of several
contexts using different instance of the same strategy, we can use flyweight
pattern to reduce the overhead. In other words, we can implement strategy as
stateless objects that those contexts can share and any residual state is
maintained by the context, which passes it in each request to the strategy
object. Shared strategies should not maintain state across invocations. |
|
Strategy |
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? |
|
Answer |
One approach is to pass
all the data that the strategy has to access into the strategy object, which
decouples the strategy object from the context. |
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? |
Answer
|
If the client code
attempts to call a method in B that is not part of A’s interface, then it
means that the client can tell the difference between a decorated component
and an undecorated one, and it depends on the decoration. It violates the
intent of the decorator pattern. In strict sense of the pattern, it is no
longer a Decorator. The decorator pattern
provides flexibilities by conforming to the interface of the components it
decorates. And it allows decorator’s presence transparent to the client and
the client can treat decorated and undecorated one uniformly. This
transparency of the decorator also lets there to be unlimited number of
decorators as needed. |
Adapter
|
Would you ever create an
Adapter that has the same interface as the object that it adapts? Would your
Adapter then be a Proxy? |
|
Answer |
An Adapter can have the
same interface as the object that it adapts because a method in the adapter
and adaptee (having the same interface) may do different operations on
different kinds of data. In this case, the Adapter probably has more
functions which requires the adaptee method.
It would still be Adapter
because a proxy is usually used as a virtual placeholder for the real subject
or to restrict access not as an interface to some classes. |
Facade
|
1) How complex must a
sub-system be in order to justify using a facade? |
|
Answer |
When there are may dependencies
between clients and the implementation classes of an abstraction, using a
façade is justified because it decouples the sub-system from clients and
other subsystems. It is still possible that the sub-system consists of one
class in case that it gets more complex as it evolves or breaking down the
subsystem into several classes helps decoupling, portability and
independence. |
|
Facade |
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? |
|
Answer |
The façade shields
clients from complicated sub-system. So, the developers or designers in the
beginning level can still implement some basic modules that do not require
the knowledge of all the complex details in the subsystem with the simple
interface provided by the façade pattern.
While to advanced and experienced developer façade pattern does not
prevent applications from using sub-system classes if they need to. |
|
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? |
|
|
Answer |
We can get the same functionality
of a Template Method using object composition instead of inheritance. The concrete class can maintain the pointer to the object that
implements a template method so that it can use functions that are needed in
the template algorithm and implement the primitive operations to carry out
its specific steps. Then the concrete class contains all steps of the
template algorithm while in inheritance case the concrete class only needs to
have specific steps. The code using
object composition would not be as clear and simple as the code using
inheritance. And if there are some changes in those invariant parts, then all
those concrete class should be changed accordingly. |
Mediator
|
Since a Mediator becomes a
repository for logic, can the code that implements this logic begin to get
overly complex, possible resembling spaghetti code? How could this potential
problem be solved? |
|
Answer |
It is possible that the
code using Mediator gets overly complex when the interactions among objects
in the system itself are complicated. One possible approach would be to
divide the mediator into a set of mediators such that we may group the
communication among objects in a hierarchical structure. I.e. Break down the system into several
subsystems and use mediator pattern for each subsystem. Even though we have
more mediators to handle, each mediator of the subsystem has simpler
structure than one mediator that controls communication in the whole system.
Then communication between those subsystems can be managed by another
mediator. |
|
1) How does the Chain of
Responsibility pattern differ from the Decorator pattern or from a linked
list? |
|
|
Answer |
The Chain of Responsibility
is used when each object does not need to take responsibilities while the
Decorator pattern is used to attach responsibilities to an object
dynamically. In the chain of
responsibility, each object may or may not accept the request and handle it.
The request keeps passed to the next object and the receipt of the request is
not even guaranteed. And each object
is not required to confirm to a shared interface as the decorator pattern is. |
|
Chain of Responsibility |
2) Is it helpful to look
at patterns from a structural perspective? In other words, if you see how a
set of patterns are the same in terms of how they are programmed, does that
help you to understand when to apply them to a design? |
|
Answer |
It would be helpful to
analyze relations between classes in different intents and use patterns
flexibly. |
Mememto
|
The authors write that the
"Caretaker" participant never operates on or examines the contents of
a memento. Can you consider a case where a Caretaker would in fact need to
know the identity of a memento and thus need the ability to examine or query
the contents of that memento? Would this break something in the pattern? |
|
Answer |
It could be useful if a
caretaker checks mementos to see if the state information in mementos is
valid. Then the caretaker and the originator are coupled and breaks the data
encapsulation boundaries in the memento pattern. |
Command
|
In the Motivation section of the Command pattern, an application's menu system is described. An application has a Menu, which in turn has MenuItems, which in turn execute commands when they are clicked. What happens if the command needs some information about the application in order to do its job? How would the command have access to such information such that new commands could easily be written that would also have access to the information they need? |
|
Answer |
One method is to have the object
of a command subclass contain information of the application it needs when
instantiating the object by passing the reference to the application or to
the information. The command object can access the information using this
reference. But the application should provide each menu item with one command
object when using this approach. Another method is to pass
the information to the execute method as parameters but each command object
does not necessarily need the same information. So, the first approach is
better to write new command such that it would have the access to the
information they need. |
|
If something has only two
to three states, is it overkill to use the State pattern? |
|
|
Answer |
When there are only two or three states, it may be better to use
conditional logic instead of using State pattern. However, if it is possible
to add more states and change states, then it is desirable to use state
pattern because it simplifies the design and adding more states is easy. State pattern also localize the
state-specific behavior and partition behavior for different states. |
|
1) What is a non-GUI
example of a flyweight? |
|
Answer |
Our project team did not adopt Flyweight pattern but it
can be used for a ballot object in online voting system. Personal information
of individual voter can be intrinsic state in the Concrete Flyweight object
and static data such as questions, choices, information about elections can
be extrinsic state, shared data. |
|
Flyweight |
2) What is the minimum configuration for
using flyweight? Do you need to be working with thousands of objects,
hundreds, tens? |
Answer |
We have to check if
replacing a set of object with relatively few shared objects after extrinsic
states are removed saves the storage.
And there must be at least two flyweights. The more flyweights are
shared, the more resources are saved.
Then flyweight saves the storage space. |
|
One issue with the Visitor
pattern involves cyclicality. When you add a new Visitor, you must make
changes to existing code. How would you work around this possible problem? |
|
Answer |
In my opinion, adding a new Visitor does not
require to change the existing code.
The visitor pattern makes it hard to add new subclasses of Element
because each new Concrete element result in a new abstract operation on
Visitor and a related implementation in every Concrete Visitor class. We can
get around this problem by providing some default implementation in Visitor
that can be inherited by most of the Concrete Visitors. |