2016-10-25 57 views
2

我有這種情況。我開始使用「處理」文檔的系統。問題是,它似乎是一個典型的場景,它開始很小,並且越來越大,一次構建一塊,現在需要重構。適當的Java設計模式以避免重複方法

每種文檔類型都有一個標識符(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個)創建一個類。我的意思是,如果這是要走的路,那就是這樣,但如果有一種我不知道的更簡單的方法,那會更好(因爲改變是在單一方法中)。

我可以做的另一件事是將所有這些方法移動到'方法'類,並且將if-else塊移動到具有docID參數(process(int docID)的單個方法,然後從主類中調用它。但那只是分裂了這個龐大的階級。這將是「更清潔」,但不是最佳。

什麼是最好的方法來清理和分割這個龐大的類,並使其可擴展(因爲將來會添加新的文檔類型)?

+4

這(寫15班)肯定是要走的路。面向對象意味着每個實體都有自己的類。不要創建[「上帝」類](https://en.wikipedia.org/wiki/God_object)。 – RealSkeptic

+1

我可能想說,因爲您仍然在處理同樣的實例「Result」,所以'Result'的返回是非常不必要的,您確實將其傳遞給方法 – SomeJavaGuy

+1

策略模式應該是這裏的方法IMO。是的,它確實要求您爲每個獨特的實現創建一個類,但同時它以一種方式簡化代碼,只要需要新實現,就不會破壞現有代碼,並且也很容易插入應用。 –

回答

1

您可以使用工廠或抽象工廠設計模式,在這種模式下,您可以獲取所需的對象,而無需指定將創建的對象的確切類別。

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); 
    } 
} 
} 
+1

當有一個對象正在構建時使用生成器模式,而問題是關於具有多個實現的方式。檢查了這一點... http://stackoverflow.com/questions/328496/when-would-you-use-the-builder-pattern –

+0

嗯,我不太清楚如何可以建設者模式適合我的情況,但感謝回答。 – antorqs

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類上分類結果類/文檔處理上的文檔數據。如果你有不同類型的其他處理,並且可以將其提取到外部類(不需要專用字段處理,私有方法調用等),則此框架完全適用。

如果不是,你應該真的考慮重構它使用多態!使每個文檔類型爲自己的對象。使用一個強大的抽象類將它們全部鏈接起來,如果你有很多方法可以在幾個但不是所有類型上共享,那麼就相應地創建子類型 - 或者使用默認方法! Java8 FTW

+0

感謝您的完整答案。我會在幾天內嘗試,所以我不能將其標記爲正確的。但確實有用。 – antorqs