From Design Patterns: Elements of Reusable Object Oriented Software Read the sections corresponding to patterns covered in the following slides.
DESIGN PRINCIPLES Modularity Cohesion Coupling Separation of concerns: modularize or separate distinct concerns into different areas, so that each has a cohesive purpose.
DESIGN PATTERNS Provide design vocabulary. Problem, solution, intent Building blocks to think about design problems Well studied part-of-solutions Gang of Four: Typical of advanced object oriented programming GRASP: General responsibility assignment software patterns / principles https://www.youtube.com/watch?v=alxqdnodyxq
POLYMORPHISM Assume there are multiple external third-party tax calculators that must be supported (such as Tax-Master and Good-As-Gold Tax-Pro); the system needs to be able to integrate with different ones. Each tax calculator has a different interface, and so there is similar but varying behavior to adapt to each of these external fixed interfaces or APIs. One product may support a raw TCP socket protocol another may offer a SOAP interface a third may offer a Java RMI interface. The implementation of each gettaxes() method will be different. TaxMasterAdapter will adapt the request to the API of Tax- Master etc.
ADAPTER Context / Problem: How to resolve incompatible interfaces, or provide a stable interface to similar components with different interfaces? Solution: Convert the original interface of a component into another interface, through an intermediate adapter object. The NextGen POS system needs to support several kinds of external third-party services, including tax calculators, credit authorization services, inventory systems, and accounting systems, among others. Each has a different API, which can't be changed. A solution is to add a level of indirection with objects that adapt the varying external interfaces to a consistent interface used within the application.
ADAPTER
ADAPTER The Adapter pattern is a specialization of the GRASP building blocks. It offers Protected Variations from changing external interfaces or thirdparty packages through the use of an Indirection object that applies interfaces and Polymorphism.
FACTORY Provide an interface for creating families of related or dependent objects without specifying their concrete classes. How to determine which class of adapter to create, such as TaxMaster-Adapter or GoodAsGoldTaxProAdapterl? If some domain object creates them, the responsibilities of the domain object are going beyond pure application logic (such as sales total calculations) and into other concerns related to connectivity with external software components.
FACTORY A common alternative in this case is to apply the Factory (or Concrete Factory) pattern, in which a Pure Fabrication "factory" object is defined to create objects. Factory objects have several advantages: Separate the responsibility of complex creation into cohesive helper objects. Hide potentially complex creation logic. Allow introduction of performance-enhancing memory management strategies, such as object caching or recycling.
FACTORY
FACTORY Example : https://www.tutorialspoint.com/design_pattern/factory_pattern.htm
SINGLETON Ensure a class only has one instance, and provide a global point of access to it. It's important for some classes to have exactly one instance. Although there can be many printers in a system, there should be only one printer spooler. There should be only one file system and one window manager. make the class itself responsible for keeping track of its sole instance.
SINGLETON IN C++ The class can ensure that no other instance can be created (by intercepting requests to create new objects), and it can provide a way to access the instance
SINGLETON WITH SUBCLASSES
STRATEGY Context / Problem How to design for varying, but related, algorithms or policies? How to design for the ability to change these algorithms or policies? Solution Define each algorithm/policy/strategy in a separate class, with a common interface.
STRATEGY The next design problem to be resolved is to provide more complex pricing logic a store-wide discount for the day, senior citizen discounts, and so forth. The pricing strategy (which may also be called a rule, policy, or algorithm) for a sale can vary. During one period it may be 10% off all sales, later it may be $10 off, if the sale total is greater than $200, and myriad other variations. How do we How to design for these varying pricing algorithms?
STRATEGY When a Sale instance is created, it can ask the factory for its pricing strategy Because of the frequently changing pricing policy (it could be every hour), it is not desirable to cache the created strategy instance in a field of the pricingstrategyfactory, but rather to re-create one each time, by reading the external property for its class name, and then instantiating the strategy.
STRATEGY Since the behavior of pricing varies by the strategy (or algorithm), we create multiple SalePricingStrategy classes, each with a polymorphic gettotal method Each gettotal method takes the Sale object as a parameter, so that the pricing strategy object can find the pre-discount price from the Sale,and then apply the discounting rule. The implementation of each gettotal method will be different: PercentDiscountPricingStrategy will discount by a percentage, and so on.
FACADE Intent: Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
FACADE Consider a programming environment that gives applications access to its compiler subsystem. Some specialized applications might need to access these classes directly. But most clients of a compiler generally don't care about details like parsing and code generation; they merely want to compile some code. For them, the powerful but low-level interfaces in the compiler subsystem only complicate their task.
FACADE To provide a higher-level interface that can shield clients from these classes, the compiler subsystem also includes a Compiler class. This class defines a unified interface to the compiler's functionality. The Compiler class acts as a facade: It offers clients a single, simple interface to the compiler subsystem, combining together the classes that implement compiler functionality without hiding them completely. The compiler facade makes life easier for most programmers without hiding the lower-level functionality from the few that need it.
BEHAVIORAL: CHAIN OF RESPONSIBILITY Consider a context-sensitive help facility for a graphical user interface. The user can obtain help information on any part of the interface just by clicking on it. The help that's provided depends on the part of the interface that's selected and its context; for example, a button widget in a dialog box might have different Help information than a similar button in the main window. If no specific help information exists for that part of the interface, then the help system should display a more general help message about the immediate context the dialog box as a whole
CHAIN OF RESPONSIBILITY In a chain of responsibility pattern, the request is handled by an implicit receiver.
PURE FABRICATION Object-oriented designs are sometimes characterized by implementing representations of concepts in the real-world as software classes This lowers the representational gap; for example a Sale and Customer class. However, there are many situations in which assigning responsibilities only to domain layer software classes leads to problems in terms of poor cohesion or coupling, or low reuse potential.
PURE FABRICATION Suppose that support is needed to save Sale instances in a relational database. By Information Expert, there is some justification to assign this responsibility to the Sale class itself, because the sale has the data that needs to be saved. But consider the following implications: The task requires a relatively large number of supporting database-oriented operations, none related to the concept of sale-ness, so the Sale class becomes incohesive. The Sale class has to be coupled to the relational database interface (such as JDBC in Java technologies), so its coupling goes up. And the coupling is not even to another domain object, but to a particular kind of database interface. Saving objects in a relational database is a very general task for which many classes need support. Placing these responsibilities in the Sale class suggests there is going to be poor reuse or lots of duplication in other classes that do the same thing
PURE FABRICATION This Pure Fabrication solves the following design problems: The Sale remains well-designed, with high cohesion and low coupling. The PersistentStorage class is itself relatively cohesive, having the sole purpose of storing or inserting objects in a persistent storage medium. The PersistentStorage class is a very generic and reusable object. Creating a pure fabrication in this example is exactly the situation in which their use is called for eliminating a bad design based on Expert, with poor cohesion and coupling, with a good design in which there is greater potential for reuse.
OBSERVER A subject and an observer All observers are notified whenever the subject undergoes a change in state. In response, each observer will query the subject to synchronize its state with the subject's state.
OBSERVER Because Subject and Observer aren't tightly coupled, they can belong to different layers of abstraction in a system. A lower-level subject can communicate and inform a higher-level observer, thereby keeping the system's layering intact. If Subject and Observer are lumped together, then the resulting object must either span two layers