基本类型偏执
Overuse of basic primitive types instead of creating small objects to represent domain concepts.
Primitive Obsession arises when primitive data types (int, string, etc.) are used excessively to represent domain concepts that deserve their own types. This reduces expressiveness and makes the code harder to maintain.
Create value objects like Email, Phone, and Address instead of using raw strings. This centralizes validation and increases both safety and readability.
class User {private String firstName;private String lastName;private String email; // Should be Email value objectprivate String phone; // Should be PhoneNumber value objectprivate String street; // Should be Address value objectprivate String city;private String zipCode; // Should be ZipCode value objectprivate String country;private String currency; // Should be Currency value objectprivate double salary; // Should be Money value objectprivate String employeeId; // Should be EmployeeId value objectprivate String socialSecurityNumber; // Should be SSN value object// Validation logic scattered and duplicatedpublic boolean isValidEmail(String email) {return email != null && email.contains("@") && email.contains(".");}public boolean isValidPhone(String phone) {return phone != null && phone.length() >= 10 && phone.matches("\\d+");}public boolean isValidZipCode(String zipCode) {return zipCode != null && zipCode.matches("\\d{5}(-\\d{4})?");}public boolean isValidEmployeeId(String employeeId) {return employeeId != null && employeeId.matches("EMP\\d{6}");}public boolean isValidSSN(String ssn) {return ssn != null && ssn.matches("\\d{3}-\\d{2}-\\d{4}");}// Methods that show lack of type safetypublic void updateContact(String email, String phone) {// Easy to accidentally swap these parameters!if (isValidEmail(email)) {this.email = email;}if (isValidPhone(phone)) {this.phone = phone;}}public void updateAddress(String street, String city, String zipCode, String country) {// Too many string parameters - easy to mix upthis.street = street;this.city = city;if (isValidZipCode(zipCode)) {this.zipCode = zipCode;}this.country = country;}public void updateEmployeeInfo(String employeeId, String ssn, double salary, String currency) {// More primitive obsession - mixing different conceptsif (isValidEmployeeId(employeeId)) {this.employeeId = employeeId;}if (isValidSSN(ssn)) {this.socialSecurityNumber = ssn;}this.salary = salary;this.currency = currency;}public String getFullAddress() {return street + ", " + city + " " + zipCode + ", " + country;}public String getFormattedSalary() {return currency + " " + String.format("%.2f", salary);}// Business logic mixed with validationpublic boolean canReceivePromotion() {return isValidEmployeeId(employeeId) &&salary > 50000 &&socialSecurityNumber != null;}// Demonstration of problems with primitive obsessionpublic static void demonstrateProblems() {User user = new User();// Easy to mix up parameters of same type// Long parameter lists with similar typesuser.updateAddress("USA", "New York", "123 Main St", "10001"); // Wrong order!// Validation logic scattered and repeated// Need to validate emails everywhere they're usedif (user.isValidEmail(email1) && user.isValidEmail(email2)) {// Do something with emails}}// Getters and setters with no validationpublic String getEmail() { return email; }public void setEmail(String email) { this.email = email; } // No validation!public String getPhone() { return phone; }public void setPhone(String phone) { this.phone = phone; } // No validation!public String getEmployeeId() { return employeeId; }public void setEmployeeId(String employeeId) { this.employeeId = employeeId; } // No validation!public String getFirstName() { return firstName; }public String getLastName() { return lastName; }}// Example of business logic that suffers from primitive obsessionclass PayrollService {// Methods with too many primitive parameterspublic double calculateTax(double salary, String currency, String country, String state) {// Complex logic using primitives instead of value objectsdouble taxRate = 0.0;if ("USA".equals(country)) {if ("CA".equals(state)) {taxRate = 0.13;} else if ("NY".equals(state)) {taxRate = 0.12;}} else if ("Canada".equals(country)) {taxRate = 0.15;}// Currency conversion logic mixed inif ("EUR".equals(currency)) {salary = salary * 1.1; // Simplified conversion}return salary * taxRate;}// Another method showing primitive obsessionpublic void sendPayslip(String email, String employeeId, double salary, String currency) {// Validation scattered here tooif (email.contains("@") && employeeId.matches("EMP\\d{6}")) {System.out.println("Sending payslip to " + email);System.out.println("Employee: " + employeeId);System.out.println("Salary: " + currency + " " + salary);}}}