diff --git a/.cursor/rules/100-java-checklist-guide.mdc b/.cursor/rules/100-java-checklist-guide.mdc index fd5ccd77..4f8a0751 100644 --- a/.cursor/rules/100-java-checklist-guide.mdc +++ b/.cursor/rules/100-java-checklist-guide.mdc @@ -5,19 +5,17 @@ alwaysApply: false --- # Create a Checklist with all Java steps to use with cursor rules for Java -## System prompt characterization +## Role -Role definition: You are a Senior software engineer with extensive experience in Java programming language and technical documentation +You are a Senior software engineer with extensive experience in Java programming language and technical documentation -## Description +## Instructions for AI Your task is to create a comprehensive step-by-step guide that follows the exact format and structure defined in the embedded template below. -## Instructions for AI - -Create a markdown file named `JAVA-DEVELOPMENT-GUIDE.md` with the following exact structure: [java-checklist-template.md](mdc:.cursor/rules/templates/java-checklist-template.md) +Create a markdown file named `CURSOR-RULES-JAVA.md` with the following exact structure: [java-checklist-template.md](mdc:.cursor/rules/templates/java-checklist-template.md) -### Restrictions +## Restrictions **MANDATORY REQUIREMENT**: Follow the embedded template EXACTLY - do not add, remove, or modify any steps, sections, or cursor rules that are not explicitly shown in the template. ### What NOT to Include: @@ -28,7 +26,6 @@ Create a markdown file named `JAVA-DEVELOPMENT-GUIDE.md` with the following exac - **ONLY** use the exact wording and structure from the template - If a cursor rule exists in the workspace but is not in the template, **DO NOT** include it - ## Output Requirements - Generate the complete markdown file following the embedded template exactly diff --git a/.cursor/rules/110-java-maven-best-practices.mdc b/.cursor/rules/110-java-maven-best-practices.mdc index 1ece680b..ab855f78 100644 --- a/.cursor/rules/110-java-maven-best-practices.mdc +++ b/.cursor/rules/110-java-maven-best-practices.mdc @@ -5,25 +5,27 @@ alwaysApply: false --- # Maven Best Practices -## System prompt characterization +## Role -Role definition: You are a Senior software engineer with extensive experience in Java software development +You are a Senior software engineer with extensive experience in Java software development -## Description +## Instructions for AI -Effective Maven usage involves robust dependency management via `` and BOMs, adherence to the standard directory layout, and centralized plugin management. Build profiles should be used for environment-specific configurations. POMs must be kept readable and maintainable with logical structure and properties for versions. Custom repositories should be declared explicitly and their use minimized, preferably managed via a central repository manager. +Update the pom.xml based on the following rules about Maven best practices. -## Table of contents +## Examples -- Rule 1: Effective Dependency Management -- Rule 2: Standard Directory Layout -- Rule 3: Plugin Management and Configuration -- Rule 4: Use Build Profiles for Environment-Specific Configurations -- Rule 5: Keep POMs Readable and Maintainable -- Rule 6: Manage Repositories Explicitly -- Rule 7: Centralize Version Management with Properties +### Table of contents -## Rule 1: Effective Dependency Management +- Example 1: Effective Dependency Management +- Example 2: Standard Directory Layout +- Example 3: Plugin Management and Configuration +- Example 4: Use Build Profiles for Environment-Specific Configurations +- Example 5: Keep POMs Readable and Maintainable +- Example 6: Manage Repositories Explicitly +- Example 7: Centralize Version Management with Properties + +### Example 1: Effective Dependency Management Title: Manage Dependencies Effectively using `dependencyManagement` and BOMs Description: Use the `` section in parent POMs or import Bill of Materials (BOMs) to centralize and control dependency versions. This helps avoid version conflicts and ensures consistency across multi-module projects. Avoid hardcoding versions directly in `` when managed elsewhere. @@ -92,9 +94,10 @@ Description: Use the `` section in parent POMs or import B + ``` -**Bad Example:** +**Bad example:** ```xml @@ -118,16 +121,17 @@ Description: Use the `` section in parent POMs or import B + ``` -## Rule 2: Standard Directory Layout +### Example 2: Standard Directory Layout Title: Adhere to the Standard Directory Layout Description: Follow Maven's convention for directory structure (`src/main/java`, `src/main/resources`, `src/test/java`, `src/test/resources`, etc.). This makes projects easier to understand and build, as Maven relies on these defaults. **Good example:** -``` +```text my-app/ ├── pom.xml └── src/ @@ -141,11 +145,12 @@ my-app/ │ └── com/example/myapp/AppTest.java └── resources/ └── test-data.xml + ``` -**Bad Example:** +**Bad example:** -``` +```text my-app/ ├── pom.xml ├── sources/ @@ -155,9 +160,10 @@ my-app/ └── tests/ └── com/example/myapp/AppTest.java + ``` -## Rule 3: Plugin Management and Configuration +### Example 3: Plugin Management and Configuration Title: Manage Plugin Versions and Configurations Centrally Description: Use `` in a parent POM to define plugin versions and common configurations. Child POMs can then use the plugins without specifying versions, ensuring consistency. Override configurations in child POMs only when necessary. @@ -198,9 +204,10 @@ Description: Use `` in a parent POM to define plugin versions + ``` -**Bad Example:** +**Bad example:** ```xml @@ -220,9 +227,10 @@ Description: Use `` in a parent POM to define plugin versions + ``` -## Rule 4: Use Build Profiles for Environment-Specific Configurations +### Example 4: Use Build Profiles for Environment-Specific Configurations Title: Employ Build Profiles for Environment-Specific Settings Description: Use Maven profiles to customize build settings for different environments (e.g., dev, test, prod) or other conditional scenarios. This can include different dependencies, plugin configurations, or properties. Activate profiles via command line, OS, JDK, or file presence. @@ -272,9 +280,10 @@ Description: Use Maven profiles to customize build settings for different enviro + ``` -**Bad Example:** +**Bad example:** ```xml @@ -285,9 +294,10 @@ Description: Use Maven profiles to customize build settings for different enviro jdbc:postgresql://prodserver/mydb + ``` -## Rule 5: Keep POMs Readable and Maintainable +### Example 5: Keep POMs Readable and Maintainable Title: Structure POMs Logically for Readability Description: Organize your `pom.xml` sections in a consistent order (e.g., project coordinates, parent, properties, dependencyManagement, dependencies, build, profiles, repositories). Use properties for recurring versions or values. Add comments for complex configurations. @@ -344,9 +354,10 @@ Description: Organize your `pom.xml` sections in a consistent order (e.g., proje + ``` -**Bad Example:** +**Bad example:** ```xml @@ -369,9 +380,10 @@ Description: Organize your `pom.xml` sections in a consistent order (e.g., proje my-app 1.0.0-SNAPSHOT + ``` -## Rule 6: Manage Repositories Explicitly +### Example 6: Manage Repositories Explicitly Title: Declare Custom Repositories Explicitly and Minimize Their Use Description: Prefer dependencies from Maven Central. If custom repositories are necessary, declare them in the `` section and `` for plugins. It's often better to manage these in a company-wide Nexus/Artifactory instance configured in `settings.xml` rather than per-project POMs. Avoid relying on transitive repositories. @@ -395,9 +407,10 @@ Description: Prefer dependencies from Maven Central. If custom repositories are + ``` -**Bad Example:** +**Bad example:** ```xml @@ -414,9 +427,10 @@ Description: Prefer dependencies from Maven Central. If custom repositories are + ``` -## Rule 7: Centralize Version Management with Properties +### Example 7: Centralize Version Management with Properties Title: Use Properties to Manage Dependency and Plugin Versions Description: Define all dependency and plugin versions in the `` section rather than hardcoding them throughout the POM. This centralizes version management, makes updates easier, reduces duplication, and helps maintain consistency across related dependencies. Use consistent property naming conventions: `maven-plugin-[name].version` for Maven plugins, simple names like `[library].version` for dependencies, and descriptive names for quality thresholds like `coverage.level`. @@ -436,22 +450,22 @@ Description: Define all dependency and plugin versions in the `` sec 3.9.10 UTF-8 UTF-8 - + 2.15.3 5.10.1 5.7.0 1.4.11 - + 3.14.0 3.5.3 3.5.3 3.5.0 - + 0.8.13 - + 80 70 @@ -501,9 +515,10 @@ Description: Define all dependency and plugin versions in the `` sec + ``` -**Bad Example:** +**Bad example:** ```xml @@ -567,4 +582,9 @@ Description: Define all dependency and plugin versions in the `` sec + ``` +## Output Requirements + +- Update the file pom.xml if something is not correct +- verify changes with the command: `mvn validate` diff --git a/.cursor/rules/112-java-maven-documentation.mdc b/.cursor/rules/112-java-maven-documentation.mdc index d7a14f0e..8342cf3b 100644 --- a/.cursor/rules/112-java-maven-documentation.mdc +++ b/.cursor/rules/112-java-maven-documentation.mdc @@ -5,52 +5,27 @@ alwaysApply: false --- # Create README-DEV.md with information about how to use the Maven project -## System prompt characterization +## Role -Role definition: You are a Senior software engineer with extensive experience in Java software development +You are a Senior software engineer with extensive experience in Java software development -## Description +## Instructions for AI When creating a README-DEV.md file for a Maven project, include ONLY the following sections with the specified Maven goals. Do NOT add any additional sections, explanations, or content beyond what is explicitly listed below. -## STRICT Structure for README-DEV.md (Template): +Create a markdown file named `README-DEV.md` with the following exact structure: [java-maven-documentation-template.md](mdc:.cursor/rules/templates/java-maven-documentation-template.md) -**IMPORTANT: Include ONLY the content specified below.** +## Restrictions ---- - -# Essential Maven Goals: - -```bash -# Analyze dependencies -./mvnw dependency:tree -./mvnw dependency:analyze -./mvnw dependency:resolve - -./mvnw clean validate -U -./mvnw buildplan:list-plugin -./mvnw buildplan:list-phase -./mvnw help:all-profiles -./mvnw help:active-profiles -./mvnw license:third-party-report - -# Clean the project -./mvnw clean - -# Clean and package in one command -./mvnw clean package - -# Run integration tests -./mvnw verify +**MANDATORY REQUIREMENT**: Follow the embedded template EXACTLY - do not add, remove, or modify any steps, sections, or cursor rules that are not explicitly shown in the template. ### What NOT to Include: -# Check for dependency updates -./mvnw versions:display-property-updates -./mvnw versions:display-dependency-updates -./mvnw versions:display-plugin-updates +- **DO NOT** create additional steps beyond what's shown in the template +- **DO NOT** expand or elaborate on sections beyond what the template shows +- **ONLY** use the exact wording and structure from the template +- If a cursor rule exists in the workspace but is not in the template, **DO NOT** include it -# Generate project reports -./mvnw site -jwebserver -p 8005 -d "$(pwd)/target/site/" -``` +## Output Requirements -**END OF TEMPLATE - DO NOT ADD ANYTHING BEYOND THIS POINT** \ No newline at end of file +- Generate the complete markdown file following the embedded template exactly +- Use proper markdown formatting with headers, code blocks, tables, and checklists +- **VERIFY**: Final output contains ONLY what appears in the embedded template diff --git a/.cursor/rules/121-java-object-oriented-design.mdc b/.cursor/rules/121-java-object-oriented-design.mdc index 0adffc05..d59499fe 100644 --- a/.cursor/rules/121-java-object-oriented-design.mdc +++ b/.cursor/rules/121-java-object-oriented-design.mdc @@ -1,52 +1,97 @@ --- -description: -globs: +description: +globs: alwaysApply: false --- # Java Object-Oriented Design Guidelines -## System prompt characterization +## Role -Role definition: You are a Senior software engineer with extensive experience in Java software development +You are a Senior software engineer with extensive experience in Java software development -## Description +## Instructions for AI -This document provides comprehensive guidelines for robust Java object-oriented design and refactoring. It emphasizes core principles like SOLID, DRY, and YAGNI, best practices for class and interface design including favoring composition over inheritance and designing for immutability. The rules also cover mastering encapsulation, inheritance, and polymorphism, and finally, identifying and refactoring common object-oriented design code smells such as God Classes, Feature Envy, and Data Clumps to promote maintainable, flexible, and understandable code. +Apply comprehensive guidelines for robust Java object-oriented design and refactoring. Follow core principles like SOLID, DRY, and YAGNI, implement best practices for class and interface design including favoring composition over inheritance and designing for immutability. Master encapsulation, inheritance, and polymorphism, and identify and refactor common object-oriented design code smells such as God Classes, Feature Envy, and Data Clumps to promote maintainable, flexible, and understandable code. -## Implementing These Principles +### Implementing These Principles These guidelines are built upon the following core principles: 1. **Adherence to Fundamental Design Principles**: Embrace foundational principles like SOLID, DRY, and YAGNI. These principles are key to building systems that are robust, maintainable, flexible, and easy to understand. 2. **Effective Class and Interface Design**: Employ best practices for designing classes and interfaces. This includes favoring composition over inheritance to achieve flexibility, programming to an interface rather than an implementation to promote loose coupling, keeping classes small and focused on a single responsibility, and designing for immutability where appropriate to enhance simplicity and thread-safety. 3. **Mastery of Core OOP Concepts**: Thoroughly understand and correctly apply the pillars of object-oriented programming: - * **Encapsulation**: Protect internal state and expose behavior through well-defined interfaces. - * **Inheritance**: Model true "is-a" relationships, ensuring subclasses are substitutable for their base types (Liskov Substitution Principle). - * **Polymorphism**: Allow objects of different types to respond to the same message in their own way, simplifying client code. +* **Encapsulation**: Protect internal state and expose behavior through well-defined interfaces. +* **Inheritance**: Model true "is-a" relationships, ensuring subclasses are substitutable for their base types (Liskov Substitution Principle). +* **Polymorphism**: Allow objects of different types to respond to the same message in their own way, simplifying client code. 4. **Proactive Code Smell Management**: Develop the ability to identify common object-oriented design "code smells" (e.g., God Class, Feature Envy, Data Clumps, Refused Bequest). Recognizing and refactoring these smells is crucial for improving the long-term health, maintainability, and clarity of the codebase. -## Table of contents - -- Rule 1: Adhere to Core Design Principles (SOLID, DRY, YAGNI) -- Rule 2: Follow Best Practices for Class and Interface Design -- Rule 3: Master Encapsulation, Inheritance, and Polymorphism -- Rule 4: Identify and Refactor Object-Oriented Design Code Smells -- Rule 5: Creating and Destroying Objects -- Rule 6: Classes and Interfaces Best Practices -- Rule 7: Enums and Annotations -- Rule 8: Method Design -- Rule 9: Exception Handling - -## Rule 1: Adhere to Core Design Principles (SOLID, DRY, YAGNI) +## Examples + +### Table of contents + +- Example 1: Apply Fundamental Software Design Principles +- Example 2: Single Responsibility Principle (SRP) +- Example 3: Open/Closed Principle (OCP) +- Example 4: Liskov Substitution Principle (LSP) +- Example 5: Interface Segregation Principle (ISP) +- Example 6: Dependency Inversion Principle (DIP) +- Example 7: DRY (Don't Repeat Yourself) +- Example 8: YAGNI (You Ain't Gonna Need It) +- Example 9: Design Well-Structured and Maintainable Classes and Interfaces +- Example 10: Effectively Utilize Core Object-Oriented Concepts +- Example 11: Encapsulation +- Example 12: Inheritance +- Example 13: Polymorphism +- Example 14: Recognize and Address Common OOD Code Smells +- Example 15: Large Class / God Class +- Example 16: Feature Envy +- Example 17: Inappropriate Intimacy +- Example 18: Refused Bequest +- Example 19: Shotgun Surgery +- Example 20: Data Clumps +- Example 21: Creating and Destroying Objects +- Example 22: Consider Static Factory Methods Instead of Constructors +- Example 23: Consider a Builder When Faced with Many Constructor Parameters +- Example 24: Enforce the Singleton Property with a Private Constructor or an Enum Type +- Example 25: Prefer Dependency Injection to Hardwiring Resources +- Example 26: Avoid Creating Unnecessary Objects +- Example 27: Classes and Interfaces Best Practices +- Example 28: Minimize the Accessibility of Classes and Members +- Example 29: In Public Classes, Use Accessor Methods, Not Public Fields +- Example 30: Minimize Mutability +- Example 31: Favor Composition Over Inheritance +- Example 32: Design and Document for Inheritance or Else Prohibit It +- Example 33: Enums and Annotations +- Example 34: Use Enums Instead of Int Constants +- Example 35: Use Instance Fields Instead of Ordinals +- Example 36: Use EnumSet Instead of Bit Fields +- Example 37: Use EnumMap Instead of Ordinal Indexing +- Example 38: Consistently Use the Override Annotation +- Example 39: Method Design +- Example 40: Check Parameters for Validity +- Example 41: Make Defensive Copies When Needed +- Example 42: Design Method Signatures Carefully +- Example 43: Return Empty Collections or Arrays, Not Nulls +- Example 44: Return Optionals Judiciously +- Example 45: Exception Handling +- Example 46: Use Exceptions Only for Exceptional Conditions +- Example 47: Use Checked Exceptions for Recoverable Conditions and Runtime Exceptions for Programming Errors +- Example 48: Favor the Use of Standard Exceptions +- Example 49: Include Failure-Capture Information in Detail Messages +- Example 50: Don't Ignore Exceptions + +### Example 1: Apply Fundamental Software Design Principles Title: Apply Fundamental Software Design Principles Description: Core principles like SOLID, DRY, and YAGNI are foundational to good object-oriented design, leading to more robust, maintainable, and understandable systems. -### Sub-Rule 1.1: Single Responsibility Principle (SRP) +### Example 2: Single Responsibility Principle (SRP) + Title: A class should have one, and only one, reason to change. Description: This means a class should only have one job or primary responsibility. If a class handles multiple responsibilities, changes to one responsibility might inadvertently affect others. **Good example:** + ```java // Good: Separate responsibilities class UserData { @@ -73,7 +118,8 @@ class UserEmailer { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: User class with multiple responsibilities class User { @@ -98,11 +144,13 @@ class User { } ``` -### Sub-Rule 1.2: Open/Closed Principle (OCP) +### Example 3: Open/Closed Principle (OCP) + Title: Software entities should be open for extension but closed for modification. Description: You should be able to add new functionality without changing existing, tested code. This is often achieved using interfaces, abstract classes, and polymorphism. **Good example:** + ```java interface Shape { double calculateArea(); @@ -129,7 +177,8 @@ class AreaCalculator { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: AreaCalculator needs modification for new shapes class AreaCalculatorBad { @@ -141,11 +190,13 @@ class Rectangle { public double width, height; /* ... */ } class Circle { public double radius; /* ... */ } ``` -### Sub-Rule 1.3: Liskov Substitution Principle (LSP) +### Example 4: Liskov Substitution Principle (LSP) + Title: Subtypes must be substitutable for their base types. Description: Objects of a superclass should be replaceable with objects of its subclasses without affecting the correctness of the program or causing unexpected behavior. **Good example:** + ```java interface Bird { void move(); @@ -174,7 +225,8 @@ public class BirdLSPExample { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: Violating LSP class Bird { @@ -205,11 +257,13 @@ public class BirdLSPViolation { } ``` -### Sub-Rule 1.4: Interface Segregation Principle (ISP) +### Example 5: Interface Segregation Principle (ISP) + Title: Clients should not be forced to depend on interfaces they do not use. Description: It's better to have many small, specific interfaces (role interfaces) than one large, general-purpose interface. This prevents classes from having to implement methods they don't need. **Good example:** + ```java // Good: Segregated interfaces interface Worker { @@ -231,7 +285,8 @@ class RobotWorker implements Worker { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: Fat interface interface IWorkerAndEater { @@ -246,18 +301,20 @@ class Human implements IWorkerAndEater { class Robot implements IWorkerAndEater { @Override public void work() { System.out.println("Robot working."); } - @Override public void eat() { + @Override public void eat() { // Robots don't eat. This method is forced and likely empty or throws exception. - throw new UnsupportedOperationException("Robots don't eat."); + throw new UnsupportedOperationException("Robots don't eat."); } } ``` -### Sub-Rule 1.5: Dependency Inversion Principle (DIP) +### Example 6: Dependency Inversion Principle (DIP) + Title: High-level modules should not depend on low-level modules. Both should depend on abstractions. Description: Abstractions (e.g., interfaces) should not depend on details. Details (concrete implementations) should depend on abstractions. This promotes loose coupling. **Good example:** + ```java // Abstraction interface MessageSender { @@ -291,14 +348,15 @@ public class DIPExample { public static void main(String args) { NotificationService emailNotifier = new NotificationService(new EmailSender()); emailNotifier.notify("Hello via Email!"); - + NotificationService smsNotifier = new NotificationService(new SMSSender()); smsNotifier.notify("Hello via SMS!"); } } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: High-level module depends directly on low-level module class EmailerBad { @@ -319,11 +377,13 @@ class NotificationServiceBad { } ``` -### Sub-Rule 1.6: DRY (Don't Repeat Yourself) +### Example 7: DRY (Don't Repeat Yourself) + Title: Avoid duplication of code. Description: Every piece of knowledge or logic must have a single, unambiguous, authoritative representation within a system. Use methods, classes, inheritance, or composition to centralize and reuse code. **Good example:** + ```java class CalculationUtils { // Centralized validation logic @@ -351,7 +411,8 @@ class CircleVolume { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: Duplicated validation logic class RectangleAreaBad { @@ -371,11 +432,13 @@ class CircleVolumeBad { } ``` -### Sub-Rule 1.7: YAGNI (You Ain't Gonna Need It) +### Example 8: YAGNI (You Ain't Gonna Need It) + Title: Implement features only when you actually need them. Description: Avoid implementing functionality based on speculation that it might be needed in the future. This helps prevent over-engineering and keeps the codebase simpler and more focused on current requirements. **Good example:** + ```java // Good: Simple class meeting current needs class ReportGenerator { @@ -388,35 +451,31 @@ class ReportGenerator { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: Over-engineered with features not currently needed class ReportGeneratorOverkill { public String generateHtmlReport(List data) { /* ... */ return "html";} - public byte generatePdfReport(List data) { + public byte[] generatePdfReport(List data) { System.out.println("Generating PDF report (not actually used yet)."); - return new byte0; + return new byte[0]; } - public byte generateExcelReport(List data) { + public byte[] generateExcelReport(List data) { System.out.println("Generating Excel report (not actually used yet)."); - return new byte0; + return new byte[0]; } // Current requirement is only for HTML, but PDF and Excel are added "just in case". } ``` -## Rule 2: Follow Best Practices for Class and Interface Design +### Example 9: Design Well-Structured and Maintainable Classes and Interfaces Title: Design Well-Structured and Maintainable Classes and Interfaces -Description: Good class and interface design is crucial for building flexible and understandable OOD systems. -- **Favor Composition over Inheritance:** Where possible, use composition (has-a relationship) to reuse code and build complex objects by assembling smaller, focused objects. Inheritance (is-a relationship) can lead to tight coupling and fragile class hierarchies if overused or misused. -- **Program to an Interface, Not an Implementation:** Depend on abstractions (interfaces or abstract classes) rather than concrete implementations. This promotes loose coupling and allows different implementations to be swapped easily. -- **Keep Classes Small and Focused:** Similar to SRP, ensure classes are not trying to do too much. Smaller classes are easier to understand, test, and maintain. -- **Design for Immutability:** Immutable objects (whose state cannot change after creation) are simpler to reason about, inherently thread-safe, and can be freely shared without risk of unintended modification. -- **Clear Naming:** Use clear, descriptive, and unambiguous names for classes, interfaces, methods, and variables that accurately reveal their purpose and intent. +Description: Good class and interface design is crucial for building flexible and understandable OOD systems. Favor composition over inheritance, program to interfaces rather than implementations, keep classes small and focused, and design for immutability where appropriate. Use clear, descriptive naming conventions. **Good example:** -(Illustrating composition and programming to an interface) + ```java // Interface (Abstraction) interface Engine { @@ -455,7 +514,7 @@ class Car { System.out.print(modelName + ": "); engine.stop(); } - + public String getModelName(){ return modelName; } } @@ -472,8 +531,8 @@ public class ClassDesignExample { } ``` -**Bad Example:** -(Illustrating tight coupling through concrete implementation and potentially problematic inheritance) +**Bad example:** + ```java // Bad: Tight coupling, not programming to an interface class BadCar { @@ -485,31 +544,20 @@ class BadCar { // If we want an electric car, this class needs significant changes or a new similar class. } class BadPetrolEngine { public void startPetrol() { System.out.println("Bad petrol engine starts."); } } - -// Bad: Potentially misusing inheritance (Vehicle IS-A PetrolEngine? Not really) -/* -abstract class Vehicle { - // ... common vehicle properties ... -} -class CarExtendsPetrolEngine extends BadPetrolEngine { // Car IS-A PetrolEngine? Incorrect modeling. - public void drive() { System.out.println("Driving car that IS-A PetrolEngine."); } -} -*/ ``` -## Rule 3: Master Encapsulation, Inheritance, and Polymorphism +### Example 10: Effectively Utilize Core Object-Oriented Concepts Title: Effectively Utilize Core Object-Oriented Concepts Description: Encapsulation, Inheritance, and Polymorphism are the three pillars of object-oriented programming. -### Sub-Rule 3.1: Encapsulation +### Example 11: Encapsulation + Title: Protect Internal State and Implementation Details -Description: -- Hide the internal state (fields) and implementation details of an object from the outside world. -- Expose a well-defined public interface (methods) for interacting with the object. -- Use access modifiers (`private`, `protected`, `default/package-private`, `public`) effectively to control visibility and protect invariants. +Description: Hide the internal state (fields) and implementation details of an object from the outside world. Expose a well-defined public interface (methods) for interacting with the object. Use access modifiers effectively to control visibility and protect invariants. **Good example:** + ```java class BankAccount { private double balance; // Encapsulated: internal state is private @@ -542,7 +590,8 @@ class BankAccount { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: Poor encapsulation, exposing internal state class UnsafeBankAccount { @@ -561,15 +610,13 @@ public class BadEncapsulationExample { } ``` -### Sub-Rule 3.2: Inheritance +### Example 12: Inheritance + Title: Model "is-a" Relationships and Ensure LSP -Description: -- Use inheritance to model true "is-a" relationships, where a subclass is a more specific type of its superclass. -- Ensure that the Liskov Substitution Principle (LSP) is followed: subclasses must be substitutable for their base types without altering the correctness of the program. -- Be cautious of deep or wide inheritance hierarchies, as they can become complex, hard to maintain, and may indicate a need for composition or different abstractions. +Description: Use inheritance to model true "is-a" relationships, where a subclass is a more specific type of its superclass. Ensure that the Liskov Substitution Principle (LSP) is followed: subclasses must be substitutable for their base types without altering the correctness of the program. **Good example:** -(See LSP good example under Rule 1.3, or consider this Animal example) + ```java abstract class Animal { private String name; @@ -601,42 +648,35 @@ public class InheritanceExample { } ``` -**Bad Example:** -(See LSP bad example under Rule 1.3, or a fragile base class example) +**Bad example:** + ```java -// Bad: Fragile base class or incorrect "is-a" relationship +// Bad: Incorrect "is-a" relationship using composition instead class Window { public void open() { System.out.println("Window opened."); } public void close() { System.out.println("Window closed."); } } -// class CarDoor extends Window { /* A CarDoor IS-A Window? Not really. It has a window, but isn't one itself. -// This leads to inheriting methods that might not make sense (e.g. a CarDoor might have a window that opens/closes, -// but the door itself doesn't open/close in the same way a house window does). -// This is better modeled with composition: CarDoor HAS-A WindowComponent. */ -// } - class BetterCarDoor { private WindowComponent window = new WindowComponent(); public void openDoor() { System.out.println("Car door opened."); } public void closeDoor() { System.out.println("Car door closed."); } public void openWindow() { window.open(); } public void closeWindow() { window.close(); } - static class WindowComponent { /* Similar to Window */ + static class WindowComponent { /* Similar to Window */ public void open() {System.out.println("Car window rolling down.");} public void close() {System.out.println("Car window rolling up.");} } } ``` -### Sub-Rule 3.3: Polymorphism +### Example 13: Polymorphism + Title: Enable Objects to Respond to the Same Message Differently -Description: -- Polymorphism allows objects of different classes (that share a common superclass or interface) to respond to the same message (method call) in their own specific ways. -- It is primarily leveraged through inheritance (method overriding) and interfaces (implementing interface methods). -- Polymorphism simplifies client code, as it can interact with different types of objects through a common interface without needing to know their concrete types. +Description: Polymorphism allows objects of different classes (that share a common superclass or interface) to respond to the same message (method call) in their own specific ways. It simplifies client code, as it can interact with different types of objects through a common interface without needing to know their concrete types. **Good example:** + ```java interface Drawable { void draw(); @@ -647,7 +687,7 @@ class CircleShape implements Drawable { } class SquareShape implements Drawable { - @Override public void draw() { System.out.println("Drawing a Square: "); } + @Override public void draw() { System.out.println("Drawing a Square: □"); } } class TriangleShape implements Drawable { @@ -662,8 +702,8 @@ public class PolymorphismExample { } public static void main(String args) { List myShapes = List.of( - new CircleShape(), - new SquareShape(), + new CircleShape(), + new SquareShape(), new TriangleShape() ); drawShapes(myShapes); @@ -671,7 +711,8 @@ public class PolymorphismExample { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: Lacking polymorphism, using type checking and casting class ShapeDrawer { @@ -694,22 +735,23 @@ class SquareShapeBad { public void drawSquare() { System.out.println("Drawing Sq class TriangleShapeBad { public void drawTriangle() { System.out.println("Drawing Triangle (Bad)."); } } ``` -## Rule 4: Identify and Refactor Object-Oriented Design Code Smells +### Example 14: Recognize and Address Common OOD Code Smells Title: Recognize and Address Common OOD Code Smells Description: Code smells are symptoms of potential underlying problems in the design. Recognizing and refactoring them can significantly improve code quality. -### Sub-Rule 4.1: Large Class / God Class +### Example 15: Large Class / God Class + Title: A class that knows or does too much. Description: Such classes violate SRP and are hard to understand, maintain, and test. Consider breaking them down into smaller, more focused classes. -**Good example:** (Separated responsibilities - see SRP Good Example) -**Bad Example:** (A single class doing parsing, validation, persistence, notification - see SRP Bad Example) -### Sub-Rule 4.2: Feature Envy +### Example 16: Feature Envy + Title: A method that seems more interested in a class other than the one it actually is in. Description: This often means the method is using data from another class more than its own. Consider moving the method to the class it's "envious" of, or introduce a new class to mediate. **Good example:** + ```java class Customer { private String name; @@ -728,7 +770,8 @@ class Address { } ``` -**Bad Example:** +**Bad example:** + ```java class Order { private double amount; @@ -738,19 +781,20 @@ class Order { // Bad: This method is more interested in Customer's Address than Order itself public String getCustomerShippingLabel() { Address addr = customer.getAddress(); // Assuming Customer has getAddress() - return customer.getName() + "\n" + addr.getStreet() + + return customer.getName() + "\n" + addr.getStreet() + "\n" + addr.getCity() + ", " + addr.getZipCode(); // Better: Move this logic to Customer class as getShippingLabel() or similar. } } -// Assume Customer and Address classes from previous example ``` -### Sub-Rule 4.3: Inappropriate Intimacy +### Example 17: Inappropriate Intimacy + Title: Classes that spend too much time delving into each other's private parts. Description: This indicates tight coupling and poor encapsulation. Classes should interact through well-defined public interfaces, not by accessing internal implementation details of others. -**Good example:** (Classes interact via public methods - see Encapsulation Good Example) -**Bad Example:** + +**Bad example:** + ```java class ServiceA { public int internalCounter = 0; // Public field, bad @@ -759,30 +803,30 @@ class ServiceA { class ServiceB { public void manipulateServiceA(ServiceA serviceA) { // Bad: Directly accessing and modifying internal state of ServiceA - serviceA.internalCounter = 100; + serviceA.internalCounter = 100; System.out.println("ServiceA counter directly set to: " + serviceA.internalCounter); // Better: ServiceA should have a method like resetCounter(int value) if this is valid behavior. } } ``` -### Sub-Rule 4.4: Refused Bequest -Title: A subclass uses only some of the methods and properties inherited from its parents, or overrides them to do nothing or throw exceptions. +### Example 18: Refused Bequest + +Title: A subclass uses only some of the methods and properties inherited from its parents. Description: This might indicate a violation of LSP or an incorrect inheritance hierarchy. The subclass might not truly be a substitutable type of the superclass. -**Good example:** (Subclass meaningfully uses/extends inherited features - see Inheritance Good Example or LSP Good Example for Ostrich) -**Bad Example:** (See LSP Bad Example with Penguin not being able to fly) -### Sub-Rule 4.5: Shotgun Surgery +### Example 19: Shotgun Surgery + Title: When a single conceptual change requires modifications in many different classes. Description: This often indicates that a single responsibility has been spread too thinly across multiple classes, leading to high coupling and difficulty in making changes. -**Good example:** (A change in tax calculation logic only requires modification in a `TaxCalculator` class, not in `Order`, `Product`, `Invoice` classes that use it.) -**Bad Example:** (If changing a discount rule requires updates in `ProductPage`, `ShoppingCart`, `CheckoutService`, and `OrderConfirmationEmail` classes, it's shotgun surgery.) -### Sub-Rule 4.6: Data Clumps -Title: Bunches of data items that regularly appear together in multiple places (e.g., parameters in multiple methods, fields in several classes). +### Example 20: Data Clumps + +Title: Bunches of data items that regularly appear together in multiple places. Description: These data clumps often represent a missing concept that should be encapsulated into its own object or record. **Good example:** + ```java // Good: Encapsulating related data into a Range object record DateRange(LocalDate start, LocalDate end) { @@ -801,12 +845,13 @@ class EventScheduler { } ``` -**Bad Example:** +**Bad example:** + ```java // Bad: Data clump (startDay, startMonth, startYear, endDay, endMonth, endYear) passed around class EventSchedulerBad { - public void scheduleEvent(String eventName, - int startDay, int startMonth, int startYear, + public void scheduleEvent(String eventName, + int startDay, int startMonth, int startYear, int endDay, int endMonth, int endYear) { // ... logic using these separate date parts ... System.out.println("Scheduling event with many date parameters."); @@ -820,12 +865,12 @@ class EventSchedulerBad { } ``` -## Rule 5: Creating and Destroying Objects +### Example 21: Creating and Destroying Objects Title: Best Practices for Object Creation and Destruction Description: Effective object creation and destruction patterns improve code clarity, performance, and maintainability. These practices help avoid common pitfalls and leverage Java's capabilities effectively. -### Sub-Rule 5.1: Consider Static Factory Methods Instead of Constructors +### Example 22: Consider Static Factory Methods Instead of Constructors Title: Use static factory methods to provide more flexibility than constructors Description: Static factory methods offer advantages like descriptive names, ability to return existing instances, and flexibility in return types. @@ -840,10 +885,10 @@ public class BigInteger { if (val > 0 && val <= MAX_CONSTANT) return posConst[(int) val]; return new BigInteger(val); } - + // Private constructor private BigInteger(long val) { /* implementation */ } - + private static final BigInteger ZERO = new BigInteger(0); private static final BigInteger[] posConst = new BigInteger[MAX_CONSTANT + 1]; } @@ -853,20 +898,20 @@ BigInteger zero = BigInteger.valueOf(0); // Clear what we're creating BigInteger hundred = BigInteger.valueOf(100); ``` -**Bad Example:** +**Bad example:** ```java public class BigInteger { // Only constructor available - less flexible public BigInteger(long val) { /* implementation */ } - + // Client code is less clear BigInteger zero = new BigInteger(0); // Not clear this could be cached BigInteger hundred = new BigInteger(100); // Creates new instance every time } ``` -### Sub-Rule 5.2: Consider a Builder When Faced with Many Constructor Parameters +### Example 23: Consider a Builder When Faced with Many Constructor Parameters Title: Use the Builder pattern for classes with multiple optional parameters Description: The Builder pattern provides a readable alternative to telescoping constructors and is safer than JavaBeans pattern. @@ -926,7 +971,7 @@ NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8) .build(); ``` -**Bad Example:** +**Bad example:** ```java // Telescoping constructor pattern - hard to read and error-prone @@ -968,7 +1013,7 @@ public class NutritionFacts { NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27); // What do these numbers mean? ``` -### Sub-Rule 5.3: Enforce the Singleton Property with a Private Constructor or an Enum Type +### Example 24: Enforce the Singleton Property with a Private Constructor or an Enum Type Title: Use enum or private constructor with static field for singletons Description: Enum-based singletons are the best way to implement singletons, providing serialization and reflection safety. @@ -979,11 +1024,11 @@ Description: Enum-based singletons are the best way to implement singletons, pro // Enum singleton - preferred approach public enum DatabaseConnection { INSTANCE; - + public void connect() { System.out.println("Connecting to database..."); } - + public void executeQuery(String query) { System.out.println("Executing: " + query); } @@ -992,13 +1037,13 @@ public enum DatabaseConnection { // Alternative: Static field with private constructor public class Logger { private static final Logger INSTANCE = new Logger(); - + private Logger() { /* private constructor */ } - + public static Logger getInstance() { return INSTANCE; } - + public void log(String message) { System.out.println("LOG: " + message); } @@ -1009,15 +1054,15 @@ DatabaseConnection.INSTANCE.connect(); Logger.getInstance().log("Application started"); ``` -**Bad Example:** +**Bad example:** ```java // Not thread-safe singleton public class BadSingleton { private static BadSingleton instance; - + private BadSingleton() {} - + public static BadSingleton getInstance() { if (instance == null) { // Race condition possible instance = new BadSingleton(); @@ -1027,7 +1072,7 @@ public class BadSingleton { } ``` -### Sub-Rule 5.4: Prefer Dependency Injection to Hardwiring Resources +### Example 25: Prefer Dependency Injection to Hardwiring Resources Title: Use dependency injection instead of hardcoded dependencies Description: Classes should not create their dependencies directly but receive them from external sources, improving testability and flexibility. @@ -1037,12 +1082,12 @@ Description: Classes should not create their dependencies directly but receive t ```java public class SpellChecker { private final Lexicon dictionary; - + // Dependency injected through constructor public SpellChecker(Lexicon dictionary) { this.dictionary = Objects.requireNonNull(dictionary); } - + public boolean isValid(String word) { return dictionary.contains(word); } @@ -1064,22 +1109,22 @@ Lexicon englishDict = new EnglishLexicon(); SpellChecker checker = new SpellChecker(englishDict); ``` -**Bad Example:** +**Bad example:** ```java // Hardwired dependency - inflexible and hard to test public class SpellChecker { private static final Lexicon dictionary = new EnglishLexicon(); // Hardcoded - + private SpellChecker() {} // Noninstantiable - + public static boolean isValid(String word) { return dictionary.contains(word); } } ``` -### Sub-Rule 5.5: Avoid Creating Unnecessary Objects +### Example 26: Avoid Creating Unnecessary Objects Title: Reuse objects when possible to improve performance Description: Object creation can be expensive. Reuse immutable objects and avoid creating objects in loops when possible. @@ -1089,13 +1134,13 @@ Description: Object creation can be expensive. Reuse immutable objects and avoid ```java public class DateUtils { // Reuse expensive objects - private static final DateTimeFormatter FORMATTER = + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - + public String formatDate(LocalDate date) { return FORMATTER.format(date); // Reuse formatter } - + // Use primitives when possible public boolean isEven(int number) { return number % 2 == 0; // No object creation @@ -1103,7 +1148,7 @@ public class DateUtils { } ``` -**Bad Example:** +**Bad example:** ```java public class DateUtils { @@ -1112,7 +1157,7 @@ public class DateUtils { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); return formatter.format(date); } - + // Unnecessary autoboxing public boolean isEven(Integer number) { return number % 2 == 0; // Creates Integer objects @@ -1120,12 +1165,12 @@ public class DateUtils { } ``` -## Rule 6: Classes and Interfaces Best Practices +### Example 27: Classes and Interfaces Best Practices Title: Design Classes and Interfaces for Maximum Effectiveness Description: Well-designed classes and interfaces are the foundation of maintainable and robust Java applications. These practices ensure proper encapsulation, inheritance, and interface design. -### Sub-Rule 6.1: Minimize the Accessibility of Classes and Members +### Example 28: Minimize the Accessibility of Classes and Members Title: Use the most restrictive access level that makes sense Description: Proper encapsulation hides implementation details and allows for easier maintenance and evolution of code. @@ -1136,24 +1181,24 @@ Description: Proper encapsulation hides implementation details and allows for ea public class BankAccount { private final String accountNumber; // Private - implementation detail private double balance; // Private - internal state - + // Package-private for testing static final double MINIMUM_BALANCE = 0.0; - + public BankAccount(String accountNumber, double initialBalance) { // Public - part of API this.accountNumber = accountNumber; this.balance = initialBalance; } - + public double getBalance() { // Public - part of API return balance; } - + public void deposit(double amount) { // Public - part of API validateAmount(amount); balance += amount; } - + private void validateAmount(double amount) { // Private - implementation detail if (amount <= 0) { throw new IllegalArgumentException("Amount must be positive"); @@ -1162,19 +1207,19 @@ public class BankAccount { } ``` -**Bad Example:** +**Bad example:** ```java public class BankAccount { public String accountNumber; // Should be private public double balance; // Should be private public static final double MINIMUM_BALANCE = 0.0; // Unnecessarily public - + public BankAccount(String accountNumber, double initialBalance) { this.accountNumber = accountNumber; this.balance = initialBalance; } - + public void validateAmount(double amount) { // Should be private if (amount <= 0) { throw new IllegalArgumentException("Amount must be positive"); @@ -1183,7 +1228,7 @@ public class BankAccount { } ``` -### Sub-Rule 6.2: In Public Classes, Use Accessor Methods, Not Public Fields +### Example 29: In Public Classes, Use Accessor Methods, Not Public Fields Title: Provide getter and setter methods instead of exposing fields directly Description: Accessor methods provide flexibility to add validation, logging, or other logic without breaking clients. @@ -1194,15 +1239,15 @@ Description: Accessor methods provide flexibility to add validation, logging, or public class Point { private double x; private double y; - + public Point(double x, double y) { this.x = x; this.y = y; } - + public double getX() { return x; } public double getY() { return y; } - + public void setX(double x) { // Can add validation or other logic if (Double.isNaN(x)) { @@ -1210,7 +1255,7 @@ public class Point { } this.x = x; } - + public void setY(double y) { if (Double.isNaN(y)) { throw new IllegalArgumentException("y cannot be NaN"); @@ -1220,13 +1265,13 @@ public class Point { } ``` -**Bad Example:** +**Bad example:** ```java public class Point { public double x; // Direct field access - no validation possible public double y; // Cannot add logic later without breaking clients - + public Point(double x, double y) { this.x = x; this.y = y; @@ -1234,7 +1279,7 @@ public class Point { } ``` -### Sub-Rule 6.3: Minimize Mutability +### Example 30: Minimize Mutability Title: Make classes immutable when possible Description: Immutable classes are simpler, safer, and can be freely shared. They are inherently thread-safe and have no temporal coupling. @@ -1245,33 +1290,33 @@ Description: Immutable classes are simpler, safer, and can be freely shared. The public final class Complex { private final double real; private final double imaginary; - + public Complex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } - + public double realPart() { return real; } public double imaginaryPart() { return imaginary; } - + // Operations return new instances instead of modifying public Complex plus(Complex c) { return new Complex(real + c.real, imaginary + c.imaginary); } - + public Complex minus(Complex c) { return new Complex(real - c.real, imaginary - c.imaginary); } - + @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Complex)) return false; Complex c = (Complex) o; - return Double.compare(c.real, real) == 0 && + return Double.compare(c.real, real) == 0 && Double.compare(c.imaginary, imaginary) == 0; } - + @Override public int hashCode() { return Objects.hash(real, imaginary); @@ -1279,33 +1324,33 @@ public final class Complex { } ``` -**Bad Example:** +**Bad example:** ```java public class Complex { private double real; // Mutable fields private double imaginary; // Mutable fields - + public Complex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } - + public double getRealPart() { return real; } public double getImaginaryPart() { return imaginary; } - + // Mutating operations - not thread-safe, harder to reason about public void plus(Complex c) { this.real += c.real; this.imaginary += c.imaginary; } - + public void setReal(double real) { this.real = real; } public void setImaginary(double imaginary) { this.imaginary = imaginary; } } ``` -### Sub-Rule 6.4: Favor Composition Over Inheritance +### Example 31: Favor Composition Over Inheritance Title: Use composition instead of inheritance when you want to reuse code Description: Composition is more flexible than inheritance and avoids the fragility of inheritance hierarchies. @@ -1317,25 +1362,25 @@ Description: Composition is more flexible than inheritance and avoids the fragil public class InstrumentedSet { private final Set s; private int addCount = 0; - + public InstrumentedSet(Set s) { this.s = s; } - + public boolean add(E e) { addCount++; return s.add(e); } - + public boolean addAll(Collection c) { addCount += c.size(); return s.addAll(c); } - + public int getAddCount() { return addCount; } - + // Delegate other methods to the wrapped set public int size() { return s.size(); } public boolean isEmpty() { return s.isEmpty(); } @@ -1344,32 +1389,32 @@ public class InstrumentedSet { } ``` -**Bad Example:** +**Bad example:** ```java // Using inheritance - fragile and error-prone public class InstrumentedHashSet extends HashSet { private int addCount = 0; - + @Override public boolean add(E e) { addCount++; return super.add(e); } - + @Override public boolean addAll(Collection c) { addCount += c.size(); return super.addAll(c); // This calls add() internally, double-counting! } - + public int getAddCount() { return addCount; } } ``` -### Sub-Rule 6.5: Design and Document for Inheritance or Else Prohibit It +### Example 32: Design and Document for Inheritance or Else Prohibit It Title: Either design classes specifically for inheritance or make them final Description: Classes not designed for inheritance can break when subclassed. Document self-use patterns or prohibit inheritance. @@ -1379,12 +1424,12 @@ Description: Classes not designed for inheritance can break when subclassed. Doc ```java // Designed for inheritance with proper documentation public abstract class AbstractProcessor { - + /** * Processes the given data. This implementation calls {@link #validate(String)} * followed by {@link #transform(String)}. Subclasses may override this method * to provide different processing logic. - * + * * @param data the data to process * @return the processed result * @throws IllegalArgumentException if data is invalid @@ -1393,7 +1438,7 @@ public abstract class AbstractProcessor { validate(data); return transform(data); } - + /** * Validates the input data. The default implementation checks for null. * Subclasses may override to provide additional validation. @@ -1403,7 +1448,7 @@ public abstract class AbstractProcessor { throw new IllegalArgumentException("Data cannot be null"); } } - + /** * Transforms the validated data. Subclasses must implement this method. */ @@ -1413,14 +1458,14 @@ public abstract class AbstractProcessor { // Or prohibit inheritance public final class UtilityClass { private UtilityClass() { /* prevent instantiation */ } - + public static String formatName(String firstName, String lastName) { return firstName + " " + lastName; } } ``` -**Bad Example:** +**Bad example:** ```java // Not designed for inheritance but not prohibited @@ -1431,19 +1476,19 @@ public class DataProcessor { String transformed = transform(validated); return finalize(transformed); } - + private String validate(String data) { /* ... */ return data; } private String transform(String data) { /* ... */ return data; } private String finalize(String data) { /* ... */ return data; } } ``` -## Rule 7: Enums and Annotations +### Example 33: Enums and Annotations Title: Effective Use of Enums and Annotations Description: Enums and annotations are powerful Java features that, when used correctly, can make code more readable, type-safe, and maintainable. -### Sub-Rule 7.1: Use Enums Instead of Int Constants +### Example 34: Use Enums Instead of Int Constants Title: Replace int constants with type-safe enums Description: Enums provide type safety, namespace protection, and additional functionality that int constants cannot offer. @@ -1456,24 +1501,24 @@ public enum Planet { VENUS (4.869e+24, 6.052e6), EARTH (5.975e+24, 6.378e6), MARS (6.419e+23, 3.393e6); - + private final double mass; // In kilograms private final double radius; // In meters private final double surfaceGravity; // In m / s^2 - + // Universal gravitational constant in m^3 / kg s^2 private static final double G = 6.67300E-11; - + Planet(double mass, double radius) { this.mass = mass; this.radius = radius; surfaceGravity = G * mass / (radius * radius); } - + public double mass() { return mass; } public double radius() { return radius; } public double surfaceGravity() { return surfaceGravity; } - + public double surfaceWeight(double mass) { return mass * surfaceGravity; // F = ma } @@ -1487,7 +1532,7 @@ for (Planet p : Planet.values()) { } ``` -**Bad Example:** +**Bad example:** ```java // Int constants - not type-safe, no namespace @@ -1496,11 +1541,11 @@ public class Planet { public static final int VENUS = 1; public static final int EARTH = 2; public static final int MARS = 3; - + // Separate arrays for data - error-prone private static final double[] MASS = {3.302e+23, 4.869e+24, 5.975e+24, 6.419e+23}; private static final double[] RADIUS = {2.439e6, 6.052e6, 6.378e6, 3.393e6}; - + public static double surfaceWeight(int planet, double mass) { // No compile-time checking - could pass any int if (planet < 0 || planet >= MASS.length) { @@ -1512,7 +1557,7 @@ public class Planet { } ``` -### Sub-Rule 7.2: Use Instance Fields Instead of Ordinals +### Example 35: Use Instance Fields Instead of Ordinals Title: Don't derive values from enum ordinals; use instance fields Description: Ordinal values can change when enum constants are reordered, making code fragile. @@ -1524,33 +1569,33 @@ public enum Ensemble { SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5), SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8), NONET(9), DECTET(10), TRIPLE_QUARTET(12); - + private final int numberOfMusicians; - - Ensemble(int size) { - this.numberOfMusicians = size; + + Ensemble(int size) { + this.numberOfMusicians = size; } - - public int numberOfMusicians() { - return numberOfMusicians; + + public int numberOfMusicians() { + return numberOfMusicians; } } ``` -**Bad Example:** +**Bad example:** ```java public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECTET; - - public int numberOfMusicians() { + + public int numberOfMusicians() { return ordinal() + 1; // Fragile - breaks if order changes } } ``` -### Sub-Rule 7.3: Use EnumSet Instead of Bit Fields +### Example 36: Use EnumSet Instead of Bit Fields Title: Replace bit field enums with EnumSet for better type safety and performance Description: EnumSet provides all the benefits of bit fields with better readability and type safety. @@ -1560,7 +1605,7 @@ Description: EnumSet provides all the benefits of bit fields with better readabi ```java public class Text { public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH } - + // EnumSet - type-safe and efficient public void applyStyles(Set