2010-05-20 44 views
2

我有一堂課,其中的大綱基本上列在下面。我的方法太具體。我怎樣才能使它更通用?

import org.apache.commons.math.stat.Frequency; 
public class WebUsageLog { 
    private Collection<LogLine> logLines; 
    private Collection<Date> dates; 

    WebUsageLog() { 
     this.logLines = new ArrayList<LogLine>(); 
     this.dates = new ArrayList<Date>(); 
    } 

    SortedMap<Double, String> getFrequencyOfVisitedSites() { 
     SortedMap<Double, String> frequencyMap = new TreeMap<Double, String>(Collections.reverseOrder()); //we reverse order to sort from the highest percentage to the lowest. 
     Collection<String> domains = new HashSet<String>(); 
     Frequency freq = new Frequency(); 
     for (LogLine line : this.logLines) { 
      freq.addValue(line.getVisitedDomain()); 
      domains.add(line.getVisitedDomain()); 
     } 

     for (String domain : domains) { 
      frequencyMap.put(freq.getPct(domain), domain); 
     } 

     return frequencyMap; 
    } 
} 

此應用程序的目的是讓我們的人力資源人員能夠查看我們發送給他們的Web使用日誌。不過,我相信隨着時間的推移,我希望能夠提供選項,不僅可以查看訪問網站的頻率,還可以查看LogLine的其他成員(例如指定類別的頻率,訪問類型[文本/ html,img/jpeg等]過濾判斷,等等)。理想情況下,我希望避免爲每種類型的數據編寫單獨的方法,並且每種方法最終看起來幾乎與方法相同。

所以,我的問題是雙重的:首先,從機械的角度來看,你能看到哪裏應該改進這種方法嗎?其次,如何讓這種方法更通用,以便它能夠處理任意數據集?

+1

如果您遵循敏捷方法,你不應該下YAGNI(你是不是要去做任何代碼需要它)的原則。說過你應該始終關注未來。 – ChrisF 2010-05-20 19:34:40

+0

那麼,我知道我至少想要getFrequencyOfCategory()和getFrequencyOfVerdict()。我可以很容易地寫兩者,但三者之間的方法非常相似,但它們都需要以不同的方式從LogLine類中提取信息,而且我不確定如何區分它們。 – EricBoersma 2010-05-20 19:41:22

+0

有序映射是一個壞主意,因爲它不允許和忽略重複鍵。除非您確定無法確定兩次使用相同的頻率,否則最好拿着ArrayList並對其進行排序。 – 2010-05-20 20:45:15

回答

2

這與Eugene的解決方案基本相同,我只是將原始方法中的所有頻率計算內容都保留下來,並且只使用策略來讓字段工作。

如果你不喜歡枚舉,你可以用接口來代替。

public class WebUsageLog { 
    private Collection<LogLine> logLines; 
    private Collection<Date> dates; 

    WebUsageLog() { 
     this.logLines = new ArrayList<LogLine>(); 
     this.dates = new ArrayList<Date>(); 
    } 

    SortedMap<Double, String> getFrequency(LineProperty property) { 
     SortedMap<Double, String> frequencyMap = new TreeMap<Double, String>(Collections.reverseOrder()); //we reverse order to sort from the highest percentage to the lowest. 
     Collection<String> values = new HashSet<String>(); 
     Frequency freq = new Frequency(); 
     for (LogLine line : this.logLines) { 
      freq.addValue(property.getValue(line)); 
      values.add(property.getValue(line)); 
     } 

     for (String value : values) { 
      frequencyMap.put(freq.getPct(value), value); 
     } 

     return frequencyMap; 
    } 

    public enum LineProperty { 
     VISITED_DOMAIN { 
      @Override 
      public String getValue(LogLine line) { 
       return line.getVisitedDomain(); 
      } 
     }, 
     CATEGORY { 
      @Override 
      public String getValue(LogLine line) { 
       return line.getCategory(); 
      } 
     }, 
     VERDICT { 
      @Override 
      public String getValue(LogLine line) { 
       return line.getVerdict(); 
      } 
     }; 

     public abstract String getValue(LogLine line); 
    } 
} 

然後給出WebUsageLog的一個實例,你可以這樣調用它:

WebUsageLog usageLog = ... 
SortedMap<Double, String> visitedSiteFrequency = usageLog.getFrequency(VISITED_DOMAIN); 
SortedMap<Double, String> categoryFrequency = usageLog.getFrequency(CATEGORY); 
+0

正是我在找的東西。我知道必須有一種方法來做到這一點,而不是明確地構建每種方法。非常感謝您的幫助。 – EricBoersma 2010-05-20 20:31:42

1

我介紹像「數據處理」爲每個計算類型的抽象,所以你可以調用單獨的處理器的每一行:

... 
     void process(Collection<Processor> processors) { 
      for (LogLine line : this.logLines) { 
       for (Processor processor : processors) { 
        processor.process(); 
       } 
      } 

      for (Processor processor : processors) { 
       processor.complete(); 
      } 
     } 
... 

public interface Processor { 
    public void process(LogLine line); 
    public void complete(); 
} 

public class FrequencyProcessor implements Processor { 
    SortedMap<Double, String> frequencyMap = new TreeMap<Double, String>(Collections.reverseOrder()); //we reverse order to sort from the highest percentage to the lowest. 
    Collection<String> domains = new HashSet<String>(); 
    Frequency freq = new Frequency(); 

    public void process(LogLine line) 
     String property = getProperty(line); 
     freq.addValue(property); 
     domains.add(property); 
    } 

    protected String getProperty(LogLine line) { 
     return line.getVisitedDomain(); 
    } 

    public void complete() 
     for (String domain : domains) { 
      frequencyMap.put(freq.getPct(domain), domain); 
     } 
    } 
} 

你也可以改變的logline API更像一個地圖,而不是強類型的line.getVisitedDomain()可以使用line.get(「VisitedDomain」),那麼你可以爲所有屬性編寫一個通用的FrequencyProcessor,只需在其構造函數中傳遞一個屬性名稱。

+0

我的問題可能有點不清楚。所有的項目都是基於頻率的,這就是如何找到我正在努力的不同項目的頻率的問題。 您寫的答案仍然讓我爲LogLine(visitedDomain,Verdict,Category等)中包含的每個類型編寫單獨的頻率方法。 – EricBoersma 2010-05-20 19:37:15

+0

您可以取出具有抽象方法getProperty(LogLine行)的AbstractProcessor。然後,代碼調用line.getVisitedDomain()的地方就是用getProperty(line)替換它。 – 2010-05-20 20:12:46

+0

@EricBoersma我已更新建議的重構以適應您的說明 – 2010-05-20 20:24:39