Factory methods eliminate the need to bind application specific classes into the code. The code only deals with the Product interface; therefore it can work with any user-defined ConcreteProduct classes. As a result, the code is not tightly bound to a particular application, rather, the factory methods defer instantation for specific applications to the subclasses.
Adding a new kind of product requires changing the abstract factory interface and all the classes that depend on it. One way to circumvent this would be to add parameters to operations that create object that specify the kind of object to be created.
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?
Since CreateMaze in its current implementation hardcodes the number of parameters passed and its type, you would need to add another factory method with multiple parameters allowing a room's size, color to be passed.
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 accomodate different numbers of parameters used by MakeRoom to both create and configure Room objects?
The MakeRoom class could be parametrized by various prototypical room objects (like size and color), which it would then copy and add to the Room. You can then change the room's composition by replacing those prototypical objects with different ones.
Either when the classes to instantiate need to be specified at runtime, or when instances of a class can have one of only a few different combinations of state. We should also use the prototype pattern to avoid building a class hierarchy of factories that parallels the class hierarchy of products.
(ii) Explain the difference between deep vs. shallow copy.
When a shallow copy is performed the original object and cloned object shares the same instance variable whereas if a deep copy were performed, the new object would contain clones of the prototype's components.
The Facade pattern is often paired with the Singleton pattern. I've seen instances of mediator patterns and/or proxy patterns used with singleton as well.
The Composite pattern consolidates system-wide conditional logic by treating composite structures and individual objects uniformly so that clients wouldn't know whether or not they're dealing with a composite object or a leaf. This avoids having to write on the client side conditional code for defining the composition of the class.
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?
It wouldn't make sense to use a composite pattern if only a few objects had children and everything else had leaves. The advantage of having a Composite class is that it provides as many common operations across Composite and Leaf classes as possible. If you were to have tons of different leaves each with methods that need to be in the composite class, the composite class could get very large and unwieldy.
A java database connection object could be a flyweight by sharing it among multiple applications.
(ii) What is the minimum configuration for using flyweight? Do you need to be working with thousands of objects, hundreds, tens?
The flyweight pattern should only be used when objects have lots of intrinsic data, and have extrinsic data that can be efficiently computed and transferred.
The proxy seems to actually complicate code compared with simply instantiating an object immediately. It however does allow us to instantiate the object only when it needs to be thus allowing for a increase in performance. It also relieves the client of doing conditional tests to determine whether to instantiate the object and it acts as the object itself so that the client is never aware that the object may never exist.
Even though the method called may not be a part of A's interface, the Decorator pattern allows the addition of other operations for specific functionality. In order to be useful though the client needs to know about the additional method. The decorator must conform to the interface of the component its decorating so thats its presence is transparent to the component's clients.
A facade pattern should be used whenever the dependencies between
the clients and the implementation classes of an abstraction become
complex enough to need further decoupling.
(ii) 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?
A group of developers may present a facade pattern to the designers to give them an idea of what functionality they're implementing without having to go through all the details of each particular subsystem. Then the developers may independently build and extend upon the subsystem code without affecting the original design specs presented. The Facade pattern is advantageous in that it shields the clients from having to directly call any of the subsystem components, thereby layering the system and its dependencies and reducing the number of objects that clients deal with.
An adapter may have the same interface as the object which it adapts. In such a case, the adapter would probably add some extra functionality to the class which it adapts to. A proxy on the other hand functions as a virtual placeholder for an object either for efficiency purposes or for access restrictions.
The command object could encapsulate the application state which may be necessary for the command recipients. Thus, every recipient will have the application information that it needs.
A decorator pattern used in modifying an object is used to enrich
the behavior of the component while chain of responsibility does not
necessarily modify the object since each member of the chain may not
respond to each request sent through the chain.
(ii) 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?
Its helpful to look at patterns from a structural perspective in determining which patterns may be of use within a particular context. Once the list of patterns has been narrowed down, one must look at the effects each pattern would have within that same context to determine which pattern would the most useful.
Since we don't set a limitation on memento information size, its possible to have a small originator writing expensive mementos. If we wanted the caretaker to limit the number of states, perhaps by removing unnecessary states, we would need to process the memento content. Since the memento contents should not be viewable by a caretaker (because of privacy issues), remembering the originator's internal states would in a sense break the rules of the memento pattern
The code implementing mediator logic can get overly complex. We could solve this problem by revising the responsibilities we have give the mediator object, allowing it to only manage the interactions between the objects rather than perform tasks that should be done by the objects the mediator is mediating. We could also try and compartmentalize the mediators by letting each group of mediators have a mediator controller that specifies which mediator should actually perform the mediating. The objects that need mediating would pass their requests to this controller which would in turn pass the request on to a group of mediators that would handle a certain group of interactions.
Yes, in the case of having real time updates of the subject, the
observer may request an immediate update from the subject without
having to go through the controller. As a result, there may be some
synchronization issues.
(ii) 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?
There may be some complex communication network between the
subjects and the observers. Debugging the system may be as simple as
checking the subjects to see if they are updating correctly, checking
the observers to see if they are recording the updates correctly, and
then debugging the communication protocol between the two.
(iii) 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).
There are many solutions the simplest of which may be building a communication protocol that handles the updates (in place of the Controller). This protocol would be responsible for buffering subject updates, checking if the system is consistent or not, sending updates to the observers, checking for consistency and sending the message to the subjects. There would be some trade offs between efficiency and consistency.
It may be overkill to use the state pattern if no more states will ever be added to the class, the behavior of the class in each state does not vary greatly, and/or the code will never have to re-read debugged or modified.
If there is common functionality in the algorithm implementation we
can use inheritance so as to prevent code duplication.
(ii) 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?
Its definitely possible that the data required by the strategy will not be available from the context's interface. We could remedy this potential problem by making the strategy an inherited class of the context or by sharing a separate data class with the context as a Flyweight object. As a result, the data could be accessed directly through the implementation. Direct access would have the benefit of a smaller interface; however, would also result in tighter coupling.
Yes, it would be possible to get the same functionality using object composition. However, dynamic composition may be a better approach when the number of compositions is very large, because the number of combinations would grow exponentially as the number of available components increases. The subclass overriding functionality however, provides a very clear and explicit mechanism by which behavior may be specialized. In a object composition system, such a mechanism needs to be provided over and over again.
One could make a visitor that is used as the default and that could be used by most of the other visitors. I guess another solution would be to use a general interface for all visitors that combine the functionality of already existing program with a newer one.