逆転調整 (Gyakuten Chousei)

2006年1月2日 (2006nen 1gatsu 2nichi)

これは、私が2000年代半ばに執筆していた「Further Enterprise Application Architecture development」の一部です。残念ながら、それ以降、多くの他のことに気を取られてしまい、これ以上の作業に取り組む時間がありませんでしたし、近い将来、時間を見つけることも難しいと考えています。そのため、この資料は非常に草稿段階のものであり、再び作業に取り組めるようになるまで、修正や更新を行う予定はありません。

動作方法 (Douasa Houhou)

調整が必要な各エントリに対して、新しいエントリを2つ作成します。1つのエントリは、以前のエントリの単純な逆転で、発生日と金額は同じで、符号が逆になります。次に、古い金額が本来どうあるべきだったかを表す新しいエントリを投稿します。

たとえば、3月の電力使用量が50kWhの記録があるとします。このイベントは当初4月5日に記録され、4月10日に処理されました。図1にオブジェクトを示します。

図1:調整前のイベント。

その後、6月1日に、間違いがあり、金額は80kWhであるべきだったことに気づきました。図2にその構造を示します。

逆転エントリが新しいイベントではなく、古いイベントに表示されることに驚くかもしれません。これは、新しいイベント自体が後で調整される可能性があり、その場合、逆転エントリを元に戻すエントリを作成したくないためです。そのため、元のイベントに配置する方が理にかなっています。また、調整済みであることを明確にするために、そのイベントを調整済みとしてマークします。

図2:調整後のイベント

逆転調整を使用すると、これらの逆転ペアに多くのエントリが生成されます。つまり、エントリのリストを見たい場合、多くの場合、すべての逆転ペアを除外したエントリを見たいということです。そのため、この情報をフィルタリングするクエリメソッドを提供する必要があります。多くのデータが関係する可能性があるため、これは通常、データベースクエリにも影響します。

使用時期 (Shiyou Jiki)

逆転調整は、エントリが不変であり、置換調整を使用できない場合の簡単な代替手段です。主な欠点は、多くのエントリが生成されることです。完了すると、以前の1つのエントリに対して3つのエントリが生成されます。これを数回行うと、多くのエントリが生成され、多くのエントリが逆転ペアになります。これをフィルタリングできますが、それでも存在するのは面倒です。

差分調整が主な代替手段です。通常、どちらを選択するかは、ユーザーがどのように情報を表示したいかによって異なります。エントリが変更可能な場合は、置換調整を使用するのが最適です。多くの場合、エントリはある日付までは変更可能で、その後は不変であることがわかります。これにより、逆転調整置換調整の組み合わせを使用することになります。

例:不正な電力使用量の逆転 (Java)

不正な電力使用量の例と、それをどのように逆転させるべきかを以下に示します。

public void setUp() {
    MfDate.setToday(2004,4,1);
    watson = new Customer("Dr Watson");
    watson.setServiceAgreement(testAgreement());
    usageEvent = new Usage(Unit.KWH.amount(50),
                 new MfDate(2004, 3, 31),
                 watson);
    eventList.add(usageEvent);
    eventList.process();
    MfDate.setToday(2004,6,1);
    replacement = new Usage(Unit.KWH.amount(70),
                    new MfDate(2004, 3, 31),
                    watson,
                    usageEvent);
    eventList.add(replacement);
    eventList.process();
}

この実装では、調整済みイベントのスロットを含む会計イベントのコンストラクタを提供します。

class AccountingEvent...

  public AccountingEvent(EventType type, MfDate whenOccurred, Subject subject, AccountingEvent adjustedEvent) {
      this.type = type;
      this.whenOccurred = whenOccurred;
      this.whenNoticed = MfDate.today();
      this.subject = subject;
      this.adjustedEvent = adjustedEvent;
      adjustedEvent.setReplacementEvent(this);
  }
private AccountingEvent adjustedEvent;

処理中に、調整済みイベントが存在する場合は、最初に逆転されます。逆転は、元の各エントリの反対のエントリを投稿するだけで済みます。イベント処理の残りの部分は、通常どおり実行できます。

class AccountingEvent...

  public void process() {
      assert !isProcessed;
      if (adjustedEvent != null) adjustedEvent.reverse();
      subject.process(this);
      markProcessed();
  }
public void reverse() {
    assert isProcessed();
    for (Entry e : getResultingEntries()) reverseEntry(e);
    for(AccountingEvent ev : getSecondaryEvents()) ev.reverse();
}

public void reverseEntry(Entry arg) {
    Entry reversingEntry = new Entry(arg.getAmount().negate(), arg.getDate());
    Account targetAccount = subject.accountFor(arg.getAccount().type());
    targetAccount.post(reversingEntry);
 }