我有这种情况。我开始使用一个“处理”文档的系统。问题是,它似乎是典型的情况,它开始变小,并且变得越来越大,一次构建一个块,现在需要重构。
每种文档类型都有一个标识符(docID),并且它们都共享相同的底层结果结构。
有一个巨大的主类可以完成所有工作但是在这个类中有几个方法(每个站点几乎有一个)有自己的逻辑。它们几乎都有相同的变化(即在将字符串设置为结果结构中的字段或进行某些计算然后在结果结构中设置字段之前格式化字符串)。
例如:
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
private void processDocs(){
Result result = new Result();
result = processDocGeneric(result);
if(docID == 1){
result = processDoc1(result);
}
else if(docID == 2){
result = processDoc2(result);
}
...
}
好的,所以我打算重构这个,我正在考虑一些我知道的设计模式,但我不想让我觉得我用火箭筒杀死了一只蟑螂。
命令模式可能是我想到的第一个,也就是战略模式。我主要担心的是,我必须为每个具有自己的processDoc方法实现的文档类型创建一个类(目前大约有15个)。我的意思是,如果这是要走的路,那就是它,但如果有一种更简单的做法,我不知道,那会更好(因为改变是在一个方法中)。
我能做的另一件事是将所有这些方法移动到'methods'类,并将if-else块移动到一个带有docID参数(process(int docID)
的方法,然后从main调用它类。但那只是分裂了庞大的阶级。它会“更清洁”但不是最佳的。
清理和拆分这个庞大的类并使其可扩展的最佳方法是什么(因为将来会添加新的文档类型)?
答案 0 :(得分:2)
您可以使用工厂或抽象工厂设计模式,在这种模式中,您可以获得所需的对象,而无需指定将要创建的对象的确切类。
答案 1 :(得分:1)
我提出了一个基于Visitable / Visitor Pattern的解决方案。这个解决方案需要对Result
类进行很少的更改,同时打开新访问对象的大门,使其成为一个易于扩展的框架。我正在大量使用Java8的默认接口方法。
Visitor
/ Visitable
接口:
public interface DocVisitor<T extends VisitableDoc> {
default void visit(T document){
switch(document.getDocId()){
case 1:
processDoc1(document);
break;
case 2:
processDoc2(document);
break;
// ... other cases...
default:
processDocGeneric(document);
break;
}
}
void processDocGeneric(VisitableDoc document);
void processDoc1(VisitableDoc document);
void processDoc2(VisitableDoc document);
}
public interface VisitableDoc {
int getDocId();
default void visit(DocVisitor visitor){
visitor.visit(this);
}
}
轻微修改Result
类:
public class Result implements VisitableDoc { // New interface declared
int getDocId(){
return docId; // This might already exist
}
// Rest is unchanged, the default implementation will suffice
}
访客实施:
public class DocProcessor implements DocVisitor<Result> {
@Override
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
@Override
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
@Override
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
}
用法:
public static final main(String[] args){
List<Result> results = // Obtain results somehow
DocProcessor processor = new DocProcessor();
for(Result result: results){
processor.visit(result);
}
}
[如何]拆分这个庞大的类并使其可扩展(因为将来会添加新的文档类型
我所做的只是将文档数据拆分为DocProcessor类上的Result类/文档处理。如果你有其他不同类型的处理,可以提取到外部类(不需要私有字段处理,私有方法调用等),这个框架完全适用。
如果没有,你应该真的考虑重构它以使用多态性!使每个Document类型成为自己的对象。使用强大的抽象类将它们全部链接起来,如果你有很多方法可以在几个但不是所有类型中共享,那么相应地创建子类型 - 或者使用默认方法! Java8 FTW
答案 2 :(得分:0)
对于这种情况适用builder pattern。
/**
*
* Hero, the class with many parameters.
*
*/
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
public Profession getProfession() {
return profession;
}
public String getName() {
return name;
}
public HairType getHairType() {
return hairType;
}
public HairColor getHairColor() {
return hairColor;
}
public Armor getArmor() {
return armor;
}
public Weapon getWeapon() {
return weapon;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("This is a ")
.append(profession)
.append(" named ")
.append(name);
if (hairColor != null || hairType != null) {
sb.append(" with ");
if (hairColor != null) {
sb.append(hairColor).append(' ');
}
if (hairType != null) {
sb.append(hairType).append(' ');
}
sb.append(hairType != HairType.BALD ? "hair" : "head");
}
if (armor != null) {
sb.append(" wearing ").append(armor);
}
if (weapon != null) {
sb.append(" and wielding a ").append(weapon);
}
sb.append('.');
return sb.toString();
}
/**
*
* The builder class.
*
*/
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
/**
* Constructor
*/
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}