2012-02-15 327 views
6

考慮下面的代碼:填充父列表元素的值

CLASS AuditProgressReport

public class AuditProgressReport 
{ 
    private List<AuditProgressReport> audit_progress_reports = null; 

    private String name = null; 
    private String description = null; 

    private int compliant; 
    private int non_compliant; 
    private int not_completed ; 

    /** 
    * 
    */ 
    public AuditProgressReport() 
    { 
     super(); 
    } 

    public AuditProgressReport(
     String name_param, 
     int compliant_param, 
     int non_compliant_param, 
     int not_completed_param) 
    { 
     super(); 

     this.name = name_param; 
     this.compliant = compliant_param; 
     this.non_compliant = non_compliant_param; 
     this.not_completed = not_completed_param; 
    } 

    public void addToCompliant(int compl_to_add_param) 
    { 
     this.compliant += compl_to_add_param; 
    } 

    public void addToNonCompliant(int non_compl_to_add_param) 
    { 
     this.non_compliant += non_compl_to_add_param; 
    } 

    public void addToNotCompleted(int not_compl_param) 
    { 
     this.not_completed += not_compl_param; 
    } 

    public void setAuditProgressReports(List<AuditProgressReport> report_category_nodes_param) 
    { 
     this.audit_progress_reports = report_category_nodes_param; 
    } 

    public List<AuditProgressReport> getAuditProgressReports() 
    { 
     return this.audit_progress_reports; 
    } 

    public void setCompliant(int compliantParam) 
    { 
     this.compliant = compliantParam; 
    } 

    public int getCompliant() 
    { 
     return this.compliant; 
    } 

    public void setNonCompliant(int nonCompliantParam) 
    { 
     this.non_compliant = nonCompliantParam; 
    } 

    public int getNonCompliant() 
    { 
     return this.non_compliant; 
    } 

    public void setNotCompleted(int notCompletedParam) 
    { 
     this.not_completed = notCompletedParam; 
    } 

    public int getNotCompleted() 
    { 
     return this.not_completed; 
    } 

    public void setName(String name_param) 
    { 
     this.name = name_param; 
    } 

    public String getName() 
    { 
     return this.name; 
    } 

    public void setDescription(String description_param) 
    { 
     this.description = description_param; 
    } 

    public String getDescription() 
    { 
     return this.description; 
    } 

    @Override 
    public String toString() 
    { 
     return ("Compliant["+this.compliant+ 
      "] Non-Compliant["+this.non_compliant+ 
      "] Not-Completed["+this.not_completed+"]"); 
    } 
} 

和類

public class Tester 
{ 
    public static void main(String[] args) 
    { 

     List<AuditProgressReport> main_level = new ArrayList<AuditProgressReport>(); 

     AuditProgressReport ar_1_1 = new AuditProgressReport("ar_1_1",0,0,0); 
     AuditProgressReport ar_1_2 = new AuditProgressReport("ar_1_2",0,0,0); 

     AuditProgressReport ar_1_1_1 = new AuditProgressReport("ar_1_1_1",0,0,0); 
     AuditProgressReport ar_1_1_2 = new AuditProgressReport("ar_1_1_2",15,65,20); 
     AuditProgressReport ar_1_1_3 = new AuditProgressReport("ar_1_1_3",20,30,50); 

     AuditProgressReport ar_1_1_1_1 = new AuditProgressReport("ar_1_1_1_1",5,5,90); 
     AuditProgressReport ar_1_1_1_2 = new AuditProgressReport("ar_1_1_1_2",55,5,40); 
     AuditProgressReport ar_1_1_1_3 = new AuditProgressReport("ar_1_1_1_3",35,35,30); 

     List<AuditProgressReport> arl_1_1_1 = new ArrayList<AuditProgressReport>(); 
     arl_1_1_1.add(ar_1_1_1_1); 
     arl_1_1_1.add(ar_1_1_1_2); 
     arl_1_1_1.add(ar_1_1_1_3); 

     ar_1_1_1.setAuditProgressReports(arl_1_1_1); 

     List<AuditProgressReport> arl_1_1 = new ArrayList<AuditProgressReport>(); 
     arl_1_1.add(ar_1_1_1); 
     arl_1_1.add(ar_1_1_2); 
     arl_1_1.add(ar_1_1_3); 

     AuditProgressReport ar_1_2_1 = new AuditProgressReport("ar_1_2_1",10,30,60); 
     AuditProgressReport ar_1_2_2 = new AuditProgressReport("ar_1_2_2",20,20,60); 



     List<AuditProgressReport> arl_1_2 = new ArrayList<AuditProgressReport>(); 
     arl_1_2.add(ar_1_2_1); 
     arl_1_2.add(ar_1_2_2); 

     ar_1_1.setAuditProgressReports(arl_1_1); 

     ar_1_2.setAuditProgressReports(arl_1_2); 

     main_level.add(ar_1_1); 
     main_level.add(ar_1_2); 


     Tester tester = new Tester(); 

     for(AuditProgressReport prog_rep : main_level) 
     { 
      tester.populateParents(prog_rep, null); 
     } 

     //TODO Now check the values... 
    } 

    private void populateParents(
     AuditProgressReport audit_progress_param, 
     AuditProgressReport parent_param) 
    { 
     List<AuditProgressReport> audit_progress = 
      audit_progress_param.getAuditProgressReports(); 

     System.out.println("name["+audit_progress_param.getName()+"]"); 

     if(parent_param != null) 
     { 
      int compl = audit_progress_param.getCompliant(); 
      int nonCompl = audit_progress_param.getNonCompliant(); 
      int notCompleted = audit_progress_param.getNotCompleted(); 

      parent_param.addToCompliant(compl); 
      parent_param.addToNonCompliant(nonCompl); 
      parent_param.addToNotCompleted(notCompleted); 
     } 

     if(audit_progress != null && ! audit_progress.isEmpty()) 
     { 
      for(AuditProgressReport prog_rep : audit_progress) 
      { 
       this.populateParents(prog_rep,audit_progress_param); 
      } 
     } 
    } 
} 

當你運行這個,你會注意到列表中父元素的值是用和的和來更新的子列表中的值。

我面臨的問題是,我想讓它通過樹而不是直接父母更新。

有沒有一種模式可以幫助我實現這個目標?

見下圖:

enter image description here

+2

對於每個節點,將其值設置爲其子值的總和。聞起來像遞歸;) – 2012-02-15 09:07:31

+0

難道你不能讓它的孩子的每個父監聽器?手動更新也會爲您節省一些麻煩。 – bdecaf 2012-02-25 09:14:31

回答

4

像別人建議我會使用Observer模式。每個父節點都會監聽兒童的變化。

但我的解決方案從@zmf的不同,因爲如果你有一個大的樹很多孩子節點,並在每次更新你來總結每一個值,你將花費大量的處理時間。

,如果你發送的唯一舊值和新值每次更新一個子節點之間的區別。我們來舉個例子。在開始使用此樹:

[12]--+--[10]-----[10] 
     | 
     +--[ 2]--+--[ ] 
       | 
       +--[ 2] 

,並更新一個孩子這樣

[12]--+--[10]-----[10] 
     | 
     +--[ 2]--+--[ 3] 
       | 
       +--[ 2] 

的是它和值「3」送其變化與方法調用父父更新的節點。 updateNode(3)。父節點只需將其當前值(在本例中爲「2」)與從子節點收到的值相加即可。因此,將更新到值「5」

[12]--+--[10]-----[10] 
     | 
     +--[ 5]--+--[ 3] 
       | 
       +--[ 2] 

新值的節點「5」將調用parent.updateNode(3)和最終的解決方案將是

[15]--+--[10]-----[10] 
     | 
     +--[ 5]--+--[ 3] 
       | 
       +--[ 2] 

恕我直言,這種解決方案更好,因爲每個updateNode()方法只需將自己的當前值與從其子節點接收到的更改進行求和,並使用接收的相同值調用其父值。您不必從每個孩子那裏獲得價值,並總結所有的價值。如果你有一棵大樹,這將爲你節省很多時間。因此,在這個例子中,當你改變從0到3的值,你會得到2調用parent.updateNode(3),每個家長都會得到更新。

2
public void updateNode(int value) { 

    if (value != this.value) { 
     this.value = value; 

     if (getParent() != null) { 
      int sum = 0; 
      for (Node n : getParent().getChildren()) { 
       sum += n.getValue(); 
      } 
      getParent.updateNode(sum); 
     } 
    } 
} 
1

其他海報的建議選用Observer pattern的。觀察者模式是Pub/Sub pattern的子集。我建議通過觀察者模式來使用它。

Observer模式和Pub/Sub模式之間的主要區別在於,在Observer模式中,Observer既是ChangeEvents的發佈者,也是消息的分派器。它基本上使每個Observable都變成一個EventDispatcher。在傳統的Pub/Sub模式中,Observables只是ChangeEvents的發佈者。 ChangeEvents發佈到一個單獨的EventDispatchingService,它處理事件需要發送到哪些訂閱者。

試圖用Observer模式跟蹤全局更改很難做到。例如,如果要計算調用addToCompliant()方法的次數,則必須在Observable的每個實例上添加Observer。使用Event Pub/Sub,您的觀察員類可以只訂閱收聽ChangeEvent的類型,它將接收所有這些類型。我用過的最好的(恕我直言)事件發佈/子庫是Google Guava's Event Bus。在你的具體情況下,我會做類似下面的事情。

public class EventBusSingleton { 
    public static final EventBus INSTANCE = new EventBus("My Event Bus"); 
} 

public class ComplianceChange { 
    private AuditProgressReport changedReport; 
    private int delta; 

    public ComplianceChange(AuditProgressReport changedReport, int delta) { 
     this.changedReport = changedReport; 
     this.delta = delta; 
    } 

    ... 
} 

public class AuditProgressReport { 

    ... 
    private AuditProgressReport parent; 

    public AuditProgressReport getParent() { 
     return parent; 
    } 

    public void addToCompliant(int delta) { 
     this.compliant += delta; 
     ComplianceChange change = new ComplianceChange(this, delta); 
     EventBusSingleton.INSTANCE.post(change); 
    } 
    ... 
} 

public class ComplianceChangeHandler { 

    @Subscribe 
    public void notifyParent(ComplianceChange event) { 
     AuditProgressReport parent = event.getChangedReport().getParent(); 
     int delta = event.getDelta(); 
     parent.addToCompliant(delta); 
    } 

    @Subscribe 
    public void somethingElse(ComplianceChange event) { 
     // Do Something Else 
    } 
} 

// Somewhere during initialization 
EventBusSingleton.INSTANCE.register(new ComplianceChangeHandler()); 
+0

我認爲Pub/Sub模式不是這個問題的最佳選擇,因爲問題太簡單了,不能使用這種模式。在這個問題中,只有直接父節點需要知道其子節點值的變化。我將使用Pub/Sub模式解決更復雜的問題,即在兩個不同包中的兩個不相關類之間進行異步通信。事實上,在這個包中,通信的兩部分在編譯時或運行時不能彼此瞭解。 – PinoSan 2012-03-01 16:27:45

0

根據您的班級名稱,我想您希望在運行時查看您的審計進度。所以,我的假設:

  • 樹形結構不會改變太多,幾乎是固定的創建後
  • 節點值經常變化,計數器的初始狀態是0

下面是一個有效的實現:

  • 每個節點維護其父節點的完整列表
  • 節點以0值插入
  • 當一個節點的值是通過將因此先前的節點值

之間的增量改變或者乾脆增加,父母的從節點的列表值更新的結構始終是最新的,節點插入仍然是可能的並且不影響現有節點。

如果許多審計線程同時運行並向結構中報告值,則必須注意併發性問題並使用AtomicInteger作爲計數器持有者。

這是一個務實的設計,真誠地我沒有找到任何匹配模式。就像排序算法一樣,在這樣的背景下嘗試使用模式可能會適得其反。