$npx -y skills add decebals/claude-code-java --skill solid-principlesSOLID principles checklist with Java examples. Use when reviewing classes, refactoring code, or when user asks about Single Responsibility, Open/Closed, Liskov, Interface Segregation, or Dependency Inversion.
| 1 | # SOLID Principles Skill |
| 2 | |
| 3 | Review and apply SOLID principles in Java code. |
| 4 | |
| 5 | ## When to Use |
| 6 | - User says "check SOLID" / "SOLID review" / "is this class doing too much?" |
| 7 | - Reviewing class design |
| 8 | - Refactoring large classes |
| 9 | - Code review focusing on design |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## Quick Reference |
| 14 | |
| 15 | | Letter | Principle | One-liner | |
| 16 | |--------|-----------|-----------| |
| 17 | | **S** | Single Responsibility | One class = one reason to change | |
| 18 | | **O** | Open/Closed | Open for extension, closed for modification | |
| 19 | | **L** | Liskov Substitution | Subtypes must be substitutable for base types | |
| 20 | | **I** | Interface Segregation | Many specific interfaces > one general interface | |
| 21 | | **D** | Dependency Inversion | Depend on abstractions, not concretions | |
| 22 | |
| 23 | --- |
| 24 | |
| 25 | ## S - Single Responsibility Principle (SRP) |
| 26 | |
| 27 | > "A class should have only one reason to change." |
| 28 | |
| 29 | ### Violation |
| 30 | |
| 31 | ```java |
| 32 | // ❌ BAD: UserService does too much |
| 33 | public class UserService { |
| 34 | |
| 35 | public User createUser(String name, String email) { |
| 36 | // validation logic |
| 37 | if (email == null || !email.contains("@")) { |
| 38 | throw new IllegalArgumentException("Invalid email"); |
| 39 | } |
| 40 | |
| 41 | // persistence logic |
| 42 | User user = new User(name, email); |
| 43 | entityManager.persist(user); |
| 44 | |
| 45 | // notification logic |
| 46 | String subject = "Welcome!"; |
| 47 | String body = "Hello " + name; |
| 48 | emailClient.send(email, subject, body); |
| 49 | |
| 50 | // audit logic |
| 51 | auditLog.log("User created: " + email); |
| 52 | |
| 53 | return user; |
| 54 | } |
| 55 | } |
| 56 | ``` |
| 57 | |
| 58 | **Problems:** |
| 59 | - Validation changes? Modify UserService |
| 60 | - Email template changes? Modify UserService |
| 61 | - Audit format changes? Modify UserService |
| 62 | - Hard to test each concern separately |
| 63 | |
| 64 | ### Refactored |
| 65 | |
| 66 | ```java |
| 67 | // ✅ GOOD: Each class has one responsibility |
| 68 | |
| 69 | public class UserValidator { |
| 70 | public void validate(String name, String email) { |
| 71 | if (email == null || !email.contains("@")) { |
| 72 | throw new ValidationException("Invalid email"); |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | public class UserRepository { |
| 78 | public User save(User user) { |
| 79 | entityManager.persist(user); |
| 80 | return user; |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | public class WelcomeEmailSender { |
| 85 | public void sendWelcome(User user) { |
| 86 | String subject = "Welcome!"; |
| 87 | String body = "Hello " + user.getName(); |
| 88 | emailClient.send(user.getEmail(), subject, body); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | public class UserAuditLogger { |
| 93 | public void logCreation(User user) { |
| 94 | auditLog.log("User created: " + user.getEmail()); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | public class UserService { |
| 99 | private final UserValidator validator; |
| 100 | private final UserRepository repository; |
| 101 | private final WelcomeEmailSender emailSender; |
| 102 | private final UserAuditLogger auditLogger; |
| 103 | |
| 104 | public User createUser(String name, String email) { |
| 105 | validator.validate(name, email); |
| 106 | User user = repository.save(new User(name, email)); |
| 107 | emailSender.sendWelcome(user); |
| 108 | auditLogger.logCreation(user); |
| 109 | return user; |
| 110 | } |
| 111 | } |
| 112 | ``` |
| 113 | |
| 114 | ### How to Detect SRP Violations |
| 115 | |
| 116 | - Class has many `import` statements from different domains |
| 117 | - Class name contains "And" or "Manager" or "Handler" (often) |
| 118 | - Methods operate on unrelated data |
| 119 | - Changes in one area require touching unrelated methods |
| 120 | - Hard to name the class concisely |
| 121 | |
| 122 | ### Quick Check Questions |
| 123 | |
| 124 | 1. Can you describe the class purpose in one sentence without "and"? |
| 125 | 2. Would different stakeholders request changes to this class? |
| 126 | 3. Are there methods that don't use most of the class fields? |
| 127 | |
| 128 | --- |
| 129 | |
| 130 | ## O - Open/Closed Principle (OCP) |
| 131 | |
| 132 | > "Software entities should be open for extension, but closed for modification." |
| 133 | |
| 134 | ### Violation |
| 135 | |
| 136 | ```java |
| 137 | // ❌ BAD: Must modify class to add new discount type |
| 138 | public class DiscountCalculator { |
| 139 | |
| 140 | public double calculate(Order order, String discountType) { |
| 141 | if (discountType.equals("PERCENTAGE")) { |
| 142 | return order.getTotal() * 0.1; |
| 143 | } else if (discountType.equals("FIXED")) { |
| 144 | return 50.0; |
| 145 | } else if (discountType.equals("LOYALTY")) { |
| 146 | return order.getTotal() * order.getCustomer().getLoyaltyRate(); |
| 147 | } |
| 148 | // Every new discount type = modify this class |
| 149 | return 0; |
| 150 | } |
| 151 | } |
| 152 | ``` |
| 153 | |
| 154 | ### Refactored |
| 155 | |
| 156 | ```java |
| 157 | // ✅ GOOD: Add new discounts without modifying existing code |
| 158 | |
| 159 | public interface DiscountStrategy { |
| 160 | double calculate(Order order); |
| 161 | boolean supports(String discountType); |
| 162 | } |
| 163 | |
| 164 | public class PercentageDiscount implements DiscountStrategy { |
| 165 | @Override |
| 166 | public double calculate(Order order) { |
| 167 | return order.getTotal() * 0.1; |
| 168 | } |
| 169 | |
| 170 | @Override |
| 171 | public boolean supports(String discountType) { |
| 172 | return "PERCENTAGE".equals(discountType); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | public class FixedDiscount implements DiscountStrategy { |
| 177 | @Override |
| 178 | public double calculate(Order |