遵循SRP时,如何避免修改一个类引发多类联动变更?
如何在遵循单一职责原则的同时,避免新增类属性时修改大量关联类?
我一直尝试遵循单一职责原则(SRP),但遇到了问题:当我在某个类中添加或移除变量时,必须修改多个访问该类的关联类。我理解这种情况有一定合理性,但肯定有办法在类中新增变量时无需修改大量其他类?以下是一个简单示例,虽仅涉及一个需修改的类,但能说明问题:
class Person { private String name; private int age; //New variable public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge(){ return age; } public void setAge(int age){ this.age = age; } } class PersonDataStorage { public void store(Person person){ write(person.getName()); //Needing to add line below to multiple classes: write(person.getAge()); } }
我目前想到的解决办法是将相关操作放在同一个类中,但这不符合SRP,还会导致类演变为“上帝类”,恳请各位提供帮助。
解决方案1:给实体类添加统一的数据导出方法
让Person类负责对外提供需要持久化的完整数据集合,外部调用类只需要获取这个集合并处理,无需关心具体字段。新增字段时,仅需修改Person内部的导出逻辑,所有关联类都不用改动。
修改后的代码示例:
import java.util.HashMap; import java.util.Map; class Person { private String name; private int age; // 新增变量 // 原有getter/setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // 新增统一获取存储字段的方法 public Map<String, Object> getStorageFields() { Map<String, Object> fields = new HashMap<>(); fields.put("name", this.name); fields.put("age", this.age); // 新增字段时,在这里添加对应键值对即可 return fields; } } class PersonDataStorage { public void store(Person person){ // 遍历所有需要存储的字段,无需逐个添加write调用 for (Map.Entry<String, Object> entry : person.getStorageFields().entrySet()) { write(entry.getValue().toString()); } } // 模拟write方法 private void write(String content) { System.out.println("Storing: " + content); } }
解决方案2:使用访问者模式分离实体与操作
如果需要支持多种不同的操作逻辑(比如不同存储介质、不同数据格式),访问者模式可以很好地分离实体类和操作类的职责。新增字段时,仅需扩展访问者接口和实体类的接受方法,所有实现了访问者接口的操作类按需更新即可。
代码示例:
// 访问者接口,定义对Person各字段的操作 interface PersonVisitor { void visitName(String name); void visitAge(int age); // 新增字段时,在这里添加对应的visit方法 } class Person { private String name; private int age; // 原有getter/setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // 接受访问者,传递自身字段 public void accept(PersonVisitor visitor) { visitor.visitName(this.name); visitor.visitAge(this.age); // 新增字段时,在这里调用对应的visit方法 } } class PersonDataStorage implements PersonVisitor { @Override public void visitName(String name) { write(name); } @Override public void visitAge(int age) { write(String.valueOf(age)); } public void store(Person person){ person.accept(this); } // 模拟write方法 private void write(String content) { System.out.println("Storing: " + content); } }
解决方案3:反射(适合字段频繁变动的简单场景)
如果不想手动维护字段列表,可以利用反射自动遍历Person类的所有字段进行存储。这种方式完全不用修改存储类,但会带来一定性能开销,且需要处理不需要存储的字段(比如用注解过滤)。
代码示例:
import java.lang.reflect.Field; class Person { private String name; private int age; // 新增变量 // 原有getter/setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } class PersonDataStorage { public void store(Person person) throws IllegalAccessException { // 遍历Person类的所有声明字段 for (Field field : person.getClass().getDeclaredFields()) { field.setAccessible(true); // 允许访问私有字段 write(field.get(person).toString()); } } // 模拟write方法 private void write(String content) { System.out.println("Storing: " + content); } }
内容的提问来源于stack exchange,提问作者fpeste
相关产品推荐
相关产品推荐

