🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.objects
Article #17249

Re: Composition Filters [uwaga dlugie]

#17249
From: Adam Przybylek
Date: Thu, 16 Aug 2007 16:28
418 lines
12432 bytes
Kamil Janiszewski napisa?(a):
> Zobaczymy jakie nowosci przyniesie przyszla wypowiedz Pana Adama
> Przybylka.

No wie;c skoro obieca?em to pisze;. W poprzednim pos'cie mówi?em, z.e 
znalaz?em cze;s'ciowo odpowiedz' na pytanie dlaczego CFs sie; nie 
upowszechni?y. Otóz. celem CFs by?o dostarczenie mechanizmu 
umoz.liwiaja;cego lepsza; separacje; zagadnien' (SoC - Separation of 
Concerns) niz. w paradygmacie obiektowym. Moje zdanie jest takie, z.e 
wykorzystuja;c CFs dla niektórych przypadków moz.na osia;gna;c' lepsza; SoC, 
ale nie ma ona wie;kszego wp?ywu na poprawe; evolvability i reusability.
Poniz.ej przyk?ad na problemy jakie powstaja; przy implementacji w Javie 
oraz próba (bezowocna) rozwia;zania ich przy pomocy dodania do Javy 
filtrów input (hipotetyczna sk?adnia).

Za?óz.my, z.e tworza;c nowy modu? chcemy w jak najwie;kszym stopniu 
wykorzystac' istnieja;ce modu?y. Ponadto na kaz.dym etapie chcemy zrobic' 
dobra; implementacje; pod aktualne wymagania, a nie pod ewentualne 
przysz?e, o których nic nie wiemy. Zapominamy o istnieniu gotowych 
pakietów Javy. Za?óz.my takz.e, z.e posiadamy w repozytorium naste;puja;ca; 
implementacje; kolejki:

public class Queue {
   protected Object[] buf;
   protected int numItems;
   protected int nextToRemove;

   public Queue(int capacity) {
     buf = new Object[capacity];
   }

   public boolean isFull() {
     return (numItems==buf.length);
   }

   public boolean isEmpty() {
     return (numItems==0);
   }

   public int size() {
     return numItems;
   }

   public boolean put(Object x) {
     if ( isFull() ) return false;
     buf[(nextToRemove+numItems) % buf.length] = x;
     numItems++;
     return true;
   }

   public Object get() {
     Object tmp=null;
     if ( !isEmpty() ) {
       tmp = buf[nextToRemove];
       numItems--;
       nextToRemove = (nextToRemove+1) % buf.length;
     }
     return tmp;
   }
}

Etap 1. Nalez.y zaimplementowac' klase; Buffer pod klasyczny problem 
producenta-konsumenta.
a) rozwia;zanie Java
public class Buffer extends Queue {

   public Buffer(int capacity) {
     super(capacity);
   }

   public synchronized boolean put(Object x) {
     while ( isFull() ) try {
       wait();
     } catch (InterruptedException e) {}
     super.put(x);
     notifyAll();
     return true;
   }

   public synchronized Object get() {
     while ( isEmpty() ) try {
       wait();
     } catch (InterruptedException e) {}
     Object tmp = super.get();
     notifyAll();
     return tmp;
   }
}

Nalez.y zauwaz.yc', z.e zagadnienie synchronizacji (zagadnienie 
przecinaja;ce) jest splecione z zagadnieniem odk?adania i pobierania 
danych (zagadnienie podstawowe).

b) rozwia;zanie CFs
public class BufferCF {
   private Queue delegate;

   filter Wait {
     delegate.isFull() => put(Object),
     delegate.isEmpty() => get()
   };
   filter Dispatch { true => delegate.* };
}
Dzia?a to w ten sposób, z.e kaz.dy komunikat przychodza;cy z zewna;trz do 
obiektu przechodzi najpierw przez filtr Wait, a naste;pnie przez filtr 
Dispatch. Pierwszy wpis w filtrze Wait mówi, aby us'pic' wa;tek wykonuja;cy 
put(Object) na pe?nym buforze, a drugi, aby us'pic' wa;tek wykonuja;cy get() 
na pustym buforze.
Na?oz.enie na metode; filtru Wait sprawia, z.e staje sie; ona synchroniczna. 
Ponadto sprawdzenie warunku (równiez. synchroniczne) i ewentualne 
rozpocze;cie metody jest atomowe.
Z kolei zastosowany filtr Dispatch mówi, aby kaz.dy komunikat (*) 
bezwarunkowo (true) przekazac' do obs?uz.enia obiektowi delegate. Gdyby 
filtr Dispatch zawiera? wie;cej wpisów rozpatrywane by by?y od lewej do 
prawej tak d?ugo az. skojarzony z któryms' warunek be;dzie spe?niony. Jes'li 
z.aden warunek nie zostanie spe?niony to rzucany jest run-time error.

Etap 2. Przychodzi nowe wymaganie - dla kaz.dego elementu wk?adanego do 
bufora nalez.y pamie;tac' date; kiedy zosta? on w?oz.ony. Ponadto umoz.liwic' 
pobranie elementu razem z ta; data;.
a) rozwia;zanie Java
public class HistoryBuffer extends Buffer {
   protected Queue delegateDates;

   public HistoryBuffer(int capacity) {
     super(capacity);
     delegateDates = new Queue(capacity);
   }

   public synchronized boolean put(Object x) {
     while ( isFull() ) try {
       wait();
     } catch (InterruptedException e) {}
     super.put(x);
     delegateDates.put( new Date() );
     notifyAll();
     return true;
   }

   public synchronized Object get() {
     while ( isEmpty() ) try {
       wait();
     } catch (InterruptedException e) {}
     Object tmp = super.get();
     delegateDates.get();
     notifyAll();
     return tmp;
   }

   public synchronized Pair getWithDate() {
     while ( isEmpty() ) try {
       wait();
     } catch (InterruptedException e) {}
     Pair tmp = new Pair( super.get(), delegateDates.get() );
     notifyAll();
     return tmp;
   }
}

b) rozwiazanie CFs
public class HistoryBufferCF {
   private Queue delegateObjects;
   private Queue delegateDates;

   public HistoryBufferCF(int capacity) {
     delegateObjects = new Queue(capacity);
     delegateDates = new Queue(capacity);
   }

   public void put(Object x) {
     delegateObjects.put(x);
     delegateDates.put(new Date());
   }

   public Object get() {
     delegateDates.get();
     return delegateObjects.get();
   }

   public Pair getWithDate() {
     return new Pair(delegateObjects.get(),delegateDates.get());
   }

   filter Wait {
     delegateObjects.isFull() => put(Object),
     delegateObjects.isEmpty() => { get(), getWithDate() }
   };
   filter Dispatch { true => this.*, true => delegateObjects.* };
}

Etap 3. Na potrzeby monitoringu nalez.y logowac' informacje o stanie 
bufora po kaz.dej transakcji.
a) rozwia;zanie Java
public class LogHistoryBuffer extends HistoryBuffer {

   public LogHistoryBuffer(int capacity) {
     super(capacity);
   }

   protected void log() {
     System.out.println("stan bufora: "+size());
   }

   public synchronized boolean put(Object x) {
     super.put(x);
     log();
     return true;
   }

   public synchronized Object get() {
     Object tmp = super.get();
     log();
     return tmp;
   }

   public synchronized Pair getWithDate() {
     Pair tmp = super.getWithDate();
     log();
     return tmp;
   }
}

b) rozwia;zanie CFs
public class LogHistoryBufferCF {
   private HistoryBufferCF delegate;

   private void log() {
     System.out.println("stan bufora: "+delegate.size());
   }

   public void put(Object x) {
     delegate.put(x);
     log();
   }

   public Object get() {
     Object tmp = delegate.get();
     log();
     return tmp;
   }

   public Pair getWithDate() {
     Pair tmp = delegate.getWithDate();
     log();
     return tmp;
   }

   filter Wait {
     delegate.isFull() => put(Object),
     delegate.isEmpty() => { get(), getWithDate() }
   };
   filter Dispatch { true => this.*, true => delegate.* };
}

W obu implementacjach zagadnienie logowania (zagadnienie przecinaja;ce) 
przeplatane jest z zagadnieniem podstawowym.

Etap 4. Stworzyc' moz.liwos'c' pobrania n kolejnych elementów w postaci 
tablicy. Pobieranie rozpocza;c' jes'li istnieje w buforze przynajmniej 
jeden element. Logowanie ma byc' pojedyncze dla kaz.dej transakcji 
(pobranie tablicy n elementów be;dzie logowane tylko raz).

a) rozwia;zanie Java
public class EnhancedLogHistoryBuffer extends HistoryBuffer {

   protected boolean lock;

   public EnhancedLogHistoryBuffer(int capacity) {
     super(capacity);
   }

   protected void lock(boolean b) {
     lock = b;
   }

   protected boolean isLock() {
     return lock;
   }

   protected void log() {
     System.out.println("stan bufora: "+size());
   }

   public synchronized boolean put(Object x) {
     super.put(x);
     log();
     return true;
   }

   public synchronized Object get() {
     while ( isEmpty()||isLock() ) try {
       wait();
     } catch (InterruptedException e) {}
     Object tmp = super.get();
     log();
     return tmp;
   }

   public synchronized Pair getWithDate() {
     while ( isEmpty()||isLock() ) try {
       wait();
     } catch (InterruptedException e) {}
     Pair tmp = super.getWithDate();
     log();
     return tmp;
   }

   public synchronized Object[] get(int n) {
     while ( isEmpty()||isLock() ) try {
       wait();
     } catch (InterruptedException e) {}
     lock(true);
     Object[] tmp = new Object[n];
     for(int i=0; i<n; i++) {
       tmp[i] = super.get();
       dates.get();
     }
     lock(false);
     log();
     return tmp;
   }

   public synchronized Pair[] getWithDate(int n) {
     while ( isEmpty()||isLock() ) try {
       wait();
     } catch (InterruptedException e) {}
     lock(true);
     Pair[] tmp = new Pair[n];
     for(int i=0; i<n; i++) tmp[i] = super.getWithDate();
     lock(false);
     log();
     return tmp;
   }
}
Implementuja;c operacje get(int) i getWithDate(int) nie moz.na wykorzystac' 
implementacji get() i getWithDate() z klasy LogHistoryBuffer poniewaz. sa; 
one splecione z zagadnieniem logowania. Poniewaz. w Javie nie ma 
moz.liwos'ci, aby niepolimorficznie wywo?ac' metode; zdefiniowana; w 
okres'lonej nadklasie, nalez.y ponownie za punkt wyjs'cia przyja;c' klase; 
HistoryBuffer. Takie rozwia;zanie wymaga ponownego zaimplementowania 
metody log.

b) rozwia;zanie CFs
public class EnhancedLogHistoryBufferCF {
   private HistoryBufferCF delegate;
   private boolean lock;

   public EnhancedLogHistoryBufferCF(int capacity) {
     delegate = new HistoryBufferCF(capacity);
   }

   public void lock(boolean b) {
     lock = b;
   }

   public boolean isLock() {
     return lock;
   }

   private void log() {
     System.out.println("stan bufora: "+delegate.size());
   }

   public void put(Object x) {
     delegate.put(x);
     log();
   }

   public Object get() {
     Object tmp = delegate.get();
     log();
     return tmp;
   }

   public Pair getWithDate() {
     Pair tmp = delegate.getWithDate();
     log();
     return tmp;
   }

   public Object[] get(int n) {
     lock(true);
     Object[] tmp = new Object[n];
     for(int i=0; i<n; i++) tmp[i] = delegate.get();
     lock(false);
     log();
     return tmp;
   }

   public Pair[] getWithDate(int n) {
     lock(true);
     Pair[] tmp = new Pair[n];
     for(int i=0; i<n; i++) tmp[i] = delegate.getWithDate();
     lock(false);
     log();
     return tmp;
   }

   filter Wait {
     delegate.isFull() => put(Object),
     delegate.isEmpty() || isLock() => { get(), getWithDate(), get(int), 
getWithDate(int) }
   };
   filter Dispatch { true => this.*, true => delegate.* };
}

Podobnie jak w przypadku rozwia;zania w Javie, trzeba ponownie 
zaimplementowac' zagadnienie logowania. Ponadto zagadnienie 
synchronizacji poprzez metode; lock zosta?o splecione z zagadnieniem 
podstawowym.

***
Wszystkie przedstawione problemy zwia;zane z przeplataniem zagadnien' 
moz.na rozwia;zac' za pomoca; AspectJ, a cze;s'c' z nich w klasycznym je;zyku OO 
umoz.liwiaja;cym niepolimorficzne wo?anie metody.

Pozdrawiam,
Adam
Technical Details
Message-ID: <fa1tpl$vru$2@news.onet.pl>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!news.onet.pl!not-for-mail
References: <f738su$kn$1@news.onet.pl> <c68j93p3t4k797gp8cimgdifl25q1on43j@4ax.com> <1186094704.244462.260290@e9g2000prf.googlegroups.com> <c8q4b3d5kr5245mvpe7frtu5siik750r0n@4ax.com> <1186147569.379046.72670@r34g2000hsd.googlegroups.com>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!news.onet.pl!not-for-mail
From: Adam Przybylek <adampap1@vp.pl>
Newsgroups: pl.comp.objects
Subject: Re: Composition Filters [uwaga dlugie]
Date: Thu, 16 Aug 2007 18:28:42 +0200
Organization: Onet.pl
Lines: 421
Message-ID: <fa1tpl$vru$2@news.onet.pl>
References: <f738su$kn$1@news.onet.pl>   <c68j93p3t4k797gp8cimgdifl25q1on43j@4ax.com>   <1186094704.244462.260290@e9g2000prf.googlegroups.com>   <c8q4b3d5kr5245mvpe7frtu5siik750r0n@4ax.com> <1186147569.379046.72670@r34g2000hsd.googlegroups.com>
NNTP-Posting-Host: 81.210.34.66
Mime-Version: 1.0
X-Trace: news.onet.pl 1187281526 32638 81.210.34.66 (16 Aug 2007 16:25:26 GMT)
X-Complaints-To: usenet@news.onet.pl
NNTP-Posting-Date: Thu, 16 Aug 2007 16:25:26 +0000 (UTC)
X-Sender: 7oaVUrxaL5umdVGseRDCgA==
In-Reply-To: <1186147569.379046.72670@r34g2000hsd.googlegroups.com>
User-Agent: Thunderbird 1.5.0.8 (Windows/20061025)
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit