Design Patterns, Singleton Implementation, and Anti-Patterns
Course Administrative Updates and Model Validation
Assignment Specification Update:
- A small bug was identified in the assignment specifications.
- An updated version of the assignment specification document was uploaded yesterday afternoon (prior to 4:00 PM).
- Students who downloaded the specification prior to 4:00 PM must re-download the updated version to ensure compliance with corrected requirements.
AI-Assisted UML Model Validation:
- Software requirements can be processed using AI models (such as GitHub Copilot or ChatGPT) to automatically generate PlantUML syntax.
- PlantUML syntax can be pasted directly into the PlantUML web interface to render standard UML diagrams.
- PlantUML Visual Elements:
- Green dots: Represent public methods.
- Red squares: Represent private methods or attributes.
- Comparative Analysis of AI Outputs:
- Copilot Output: Generates detailed class hierarchies, abstract classes, associations, and explicit function declarations. While detailed, it carries a risk of overengineering.
- Historical ChatGPT Benchmark (Judy's Evaluation): Produced a starkly contrasting structure with zero inheritance relationships, relying entirely on bidirectional associations.
- Evaluating AI UML Quality:
- Verification against functional requirements and use cases.
- Assessment of design quality (detecting lack of inheritance vs. overengineering).
- Verification of semantic correctness and internal consistency.
Transitioning Models to Code:
- Class Diagrams and State Diagrams guide the implementation of object-oriented structural design:
- Class Diagrams: Establish class definitions, inheritance hierarchies, structural relationships, attributes, access levels, and method signatures.
- State Diagrams: Dictate internal execution logic, state transitions, and control flow inside class methods.
Software Quality and Clean Code Attributes:
- Key clean code attributes (reviewed from Week 3):
- Naming conventions
- Code structure
- Comments
- Documentation
- Core software quality attributes essential for building durable, long-term software solutions:
- Maintainability
- Clarity
- Testability
- Portability
Foundations of Software Design Patterns
Code Reuse vs. Design Pattern Reuse:
- Code Libraries: Importing external libraries allows direct code reuse, saving development time and providing confidence through community testing and quality validation.
- Design Patterns: Represent structural and conceptual reuse rather than copying exact code snippets. They provide proven frameworks for recurring structural, behavioral, and class requirements.
Elements of a Pattern Context:
- Context: The specific environment and scenario in which the problem occurs.
- Problem: The recurring issue or challenge that needs to be solved.
- Solution: The structural framework or strategy that resolves the issue.
Real-World Analogies of Pattern Recognition:
- Rubik's Cube: Successful resolution requires recognizing the current spatial configuration (state) and executing specific predetermined series of rotations (moves) to transition to the solved state.
- Chess: Master chess players identify specific board states and execute proven strategic moves or opening move sequences to secure positional advantages.
Origins and Definitions of Design Patterns:
- Christopher Alexander Definition (Building Architecture): "Each pattern describes a problem which occurs over and over again in our environment and then describes the core of the solution to that problem in such a way that you can use the solution a million times over without ever doing it the same way twice."
- The Gang of Four (GoF): In 1994, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides published Design Patterns: Elements of Reusable Object-Oriented Software.
- Historical Scope: Formulated using object-oriented languages (such as C++), documenting 23 fundamental design patterns categorized into three primary domains.
The Three Classifications of GoF Design Patterns:
- Creational Patterns: Address object instantiation mechanisms. They abstract and hide creation logic rather than relying directly on direct instantiation (e.g., Book book = new Book()), providing creation flexibility.
- Structural Patterns: Focus on class and object composition, organizing inheritance and interface hierarchies to form larger software structures.
- Behavioral Patterns: Define how dynamic object instances interact, pass messages, and distribute algorithmic responsibilities among each other.
Classification Matrix by Type and Scope:
- Design patterns are categorized by type (Creational, Structural, Behavioral) and scope (Class vs. Object):
- Creational Class Scope: Factory Method
- Creational Object Scope: Abstract Factory, Builder, Prototype, Singleton
- Structural Class Scope: Adapter (Class)
- Structural Object Scope: Adapter (Object), Bridge, Composite, Decorator, Facade, Flyweight, Proxy
- Behavioral Class Scope: Interpreter, Template Method
- Behavioral Object Scope: Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy, Visitor
Four Essential Elements of a Design Pattern:
- 1. Name: A precise design handle used to communicate concepts and structures succinctly among developers.
- 2. Problem: Explains the context, scenario, and explicit conditions required for the pattern to be applicable.
- 3. Solution: An abstract template describing the components, relationships, responsibilities, and collaborations without committing to a specific concrete implementation.
- 4. Consequences: The results, architectural impact, positive outcomes, and potential negative trade-offs associated with applying the pattern.
Process for Implementing Design Patterns:
- 1. Thoroughly understand the pattern's intent, scope, and impact on system architecture.
- 2. Study sample code and corresponding UML class/sequence diagrams.
- 3. Evaluate existing codebase classes that will be altered or created by integrating the pattern.
- 4. Explicitly define class structures, interfaces, and inheritance relationships.
The Singleton Design Pattern
Intent and Classification:
- Category: Creational Pattern.
- Scope: Object Level.
- Intent: Ensure that a class has exactly one instance while providing a global point of access to that single instance.
Applicability Criteria:
- There must be strictly one instance of a class required across the entire application runtime.
- The single instance must be accessible to client components via a well-known, globally accessible access point.
- The sole instance must be extensible through subclassing, allowing clients to utilize an extended instance without altering their codebase.
Core Implementation Steps:
- 1. Private Constructor: Declare the default constructor as private to prevent client code from directly instantiating the class using the new operator.
- 2. Private Static Instance Field: Store the single created instance in a private static field within the class.
- 3. Public Static Creation Method: Implement a public static creation/accessor method (e.g., getInstance()) that invokes the private constructor on initial call and subsequently returns the cached instance.
UML Diagrammatic Representation:
- Structure: Contains a private static instance variable, a private constructor, and a public static getInstance() method.
- Graphical Indicator: Represented in class diagrams by a self-association loop pointing back to the class itself.
Initialization Strategies:
- Lazy Initialization:
- Implementation: The static instance field is set to null initially. Instantiation occurs inside getInstance() only when invoked for the first time (if (instance == null) { instance = new Singleton(); }).
- Advantage: Conserves memory by delaying object instantiation until it is explicitly needed.
- Disadvantage: Incurs computational overhead due to performing null checks on every invocation of getInstance().
- Eager Initialization:
- Implementation: The static instance field is instantiated immediately upon class loading (private static Singleton instance = new Singleton();).
- Advantage: Saves computational execution time during runtime by eliminating conditional null checks inside getInstance().
- Disadvantage: Consumes system memory immediately upon class loading, regardless of whether the instance is actually used.
- Application Note: Either lazy or eager initialization may be utilized for implementing game state singletons (such as GameState in Assignment 2).
Concrete Example: Android Clicker Scoreboard Architecture:
- Application Scenario: An Android game requires tracking how many times a user taps a moving target across fixed time intervals and displaying the updated score across multiple screen activities (Activity1_Start and Activity2_Play).
- Failure without Singleton: Creating separate instances of AccountTracker in each activity results in isolated countValue state. Hits scored in Activity2_Play fail to reflect in Activity1_Start.
- Solution with Singleton: Implementing AccountTracker as a Singleton ensures both Activity1_Start and Activity2_Play access the exact same underlying object instance, synchronizing click scores seamlessly across the app.
Singleton Controversies and Anti-Patterns
Criticisms of the Singleton Pattern:
- Violation of Object-Oriented Principles: Suppressing public constructors breaks standard OOP creation mechanisms.
- Global State Hazards: Introduces global state into an application, introducing hidden dependencies, architectural rigidity, and unexpected side effects.
- Concurrency and Thread Safety Issues: Multithreaded environments risk generating multiple instances if lazy initialization is executed simultaneously without explicit synchronization mechanisms.
- Java Reflection Vulnerability: Tools such as Java Reflection (java.lang.reflect) can override private constructor access modifiers, instantiating new objects and destroying singleton guarantees.
Definition of Anti-Patterns:
- Common design practices or architectural choices that initially appear beneficial but ultimately prove detrimental to software quality, creating negative trade-offs that outweigh any initial advantages.
Specific Anti-Patterns Catalog:
- 1. The Blob (God Object / Monster Class):
- Description: A massive class or package that takes on excessive responsibilities, accumulating unrelated methods and data fields.
- Identification Rule: If a class's functionality cannot be concisely summarized in a single simple sentence, it has accumulated too much responsibility and must be refactored.
- Resolution: Decompose the class into smaller, single-responsibility components.
- 2. The Childless Blob:
- Description: A class that relies on extensive internal conditional checks, flags, and constraints to dictate behavior across operational roles rather than using polymorphism.
- Concrete Example: A Person class storing a role string attribute ("author", "customer", or "librarian"). Methods like loanBook() rely on repetitive if (role == "customer") conditionals.
- Drawbacks: Resulting code is unmaintainable, messy, and difficult to extend. Adding a new role requires modifying conditional logic across every single method in the class.
- Resolution: Replace conditional roles with class inheritance and polymorphism by defining a base Person class and dedicated subclasses (Author, Customer, Librarian).
- 3. The Golden Hammer:
- Description: Forcing a familiar programming language, framework, design pattern, or tool onto every software problem regardless of suitability ("when all you have is a hammer, everything looks like a nail").
- Visual Metaphor: A child's shape-sorting box where every distinct geometric block is forcibly shoved into the square hole.
- Example: Using JavaScript universally for front-end web development, back-end server logic, native Android apps, and native iOS apps without evaluating native tools.
- Resolution: Maintain continuous learning, objectively evaluate technology options, set personal biases aside, and choose the optimal tool for each specific problem.
- Counter Anti-Pattern (Bleeding-Edge Instability): Continually swapping technologies and using unstable, experimental libraries purely because they are new, degrading codebase readability and team collaboration.