Domino 9 und frühere Versionen > Entwicklung

Option Declare in Masken

<< < (3/4) > >>

TMC:

--- Zitat von: koehlerbv am 30.10.04 - 21:39:31 ---Irgendwer hat heute im Moderatorenboard einen wirklich hervorrragenden Beitrag zu den Forumsregeln gepostet. Dabei stand auch etwas zu Doppelpostings - und warum man sie nicht (gleich) machen soll.
--- Ende Zitat ---

Die Begründung steht ja oben (im zeitlichen Zusammenhang im Bezug auf die AW). Außerdem wurden auch alle Regeln von mir eingehalten (Links etc.). Vielmehr sehe ich es so, dass die Antwort auch anderen Fragenden (die nicht der deutschen Sprache mächtig sind) weiterhilft.

Matthias

Semeaphoros:
Bernhard: Ich halte das hier nicht für ein Doppelposting in dem Sinne, wie das in den geplanten Forumsregeln drinsteht. Ich halte es aber für ungeschickt, diese noch im Fluss und in der Diskussion befindlichen Forumsregeln hier zu erwähnen, das gehört hier definitiv nicht hin.

Zu den Options, im Prinzip stimmt das, was Du sagst, Bernhard. Trotzdem, es ist in LS tatsächlich nicht vollständig durchgezogen, und von Diskussionen andernorts ist mir irgendwann mal klar geworden, dass es auch in diesem Bereich eine Grauzone gibt. Ich bin mit Matthias einverstanden, dass wenn Option Declare in den globalen Options der Maske gesetzt ist, dass sich das durch die ganze Maske hindurch durchziehen müsste, das würde eigentlich auch dem OO-Modell entsprechen, denn die eingebetteten Objekte sind ja von ihrer Mutter nicht unabhängig, sprich es sind nicht wirklich - wie Du es siehst - unabhängige Module. ScriptLibs sind etwas anderes, denn sie sine gekapselt, nicht jedoch Routinen, die innerhalb der Maske definiert werden. Sprich, der Unterschied ist hier der, ob der Quellcode von extern eingebunden wird oder ob er tatsächlich innerhalb der Maskendefinition vorhanden ist. So haben globale Einstellungen ja durchaus Einfluss auf die einzelnen Events und nach Deiner Definition sollten die Events ja eigene Module darstellen.

Wir befinden uns hier teilweise in einem Bereich, in dem man die Logik abschalten muss und akzeptieren muss, dass die Grenzen hier reine Definitionssache sind und wir müssen einfach den Entscheid, den die Architekten bei Iris einst getroffen haben, schlichtweg akzeptieren.

Unschön dabei ist der von mir oben erwähnte Fall, wo man in den Shared Actions zwar Option Declare schön säuberlich definieren kann und der Compiler igonriert simpel diese Einstellung. Maureen Leland, die Chefarchitektin des Designers, hat sich dazu mal geäussert und die Gründe dargelegt, die dabei im Team diskutiert wurden: es gibt tatsächlich etwa gleichviele Gründe dafür wie dagegen. Unschön ist, dass das zwar irgendwo versteckt dokumentiert ist, aber der Designer keine Warnung abgibt, dass die Option an dieser Stelle unwirksam ist.

Marinero Atlántico:

--- Zitat von: Semeaphoros am 31.10.04 - 01:45:32 ---eingebetteten Objekte sind ja von ihrer Mutter nicht unabhängig, sprich es sind nicht wirklich - wie Du es siehst - unabhängige Module.

--- Ende Zitat ---
Yup. Guter Punkt und ich stimme 100% überein (ausser die Benutzung von Mutter in diesem Kontext, aber da mag ich ein wenig fanatisiert sein).
Die UML spezifiziert 2 besondere Arten von Ganzes-Teile Beziehungen, d.h. Container (hier Maske) has [1, lots of] in Maske enthaltene Objekte eines bestimmten Typs (hier: Buttons).
Ganzes-Teile Beziehungen sind wiederum eine besonder Untergruppe von Assoziationen. Assoziationen haben nichts, null, nil, nada, zilch mit Vererbung zu tun. Wg. dieser fundamentalen Unterscheidung ist der Begriff Container-Objekt für Ganzes-Teile Beziehung allgemein gebräuchlicher als Parent/Mutter/Vater etc., da mit letzeren allgemein Vererbungsphänomene bezeichnet werden, aber das nur am Rande.*


1. Aggregation: 1 Auto hat 4 Räder. Das Auto ist ohne die Räder nicht komplett. Die Räder existieren aber für sich selber, dh. können potentiell länger und unabhängig vom Auto leben. Wie noch zu sehen sein wird, gibt es auch Fälle, wo die abhängigen Objekte von mehreren Container-Objekten gleichzeitig verwendet werden können. 
2. Komposition (stärkere Beziehung): Das assoziierte Objekt kann über seinen gesamten Lebenszyklus nur zu einem Ganzen gehören und seine Existenz ist von der Existenz des Container-Objektes, zu dem er assoziiert ist, abhängig.
Beispiel: Das Blatt von baumA kann nicht mehr von baumB benutzt werden, nachdem baumA abgestorben ist oder baumA die Aktivität werfeBlattAbEsWirdWinter() durchgeführt hat. baumB muss vielmehr das Blatt ganz neu erzeugen.
 
Wenn code hinter einem Button nicht in einer Skript-Bibliothek enthalten ist, sondern direkt in den Button hineinprogrammiert wird, dann wird dieser code in der Maske geboren und ist in seinem Lebenszyklus 100% an die Maske gebunden, dh. er verschwindet, wenn die Maske gelöscht wird (Kompositions-Beziehung)
Es würde Sinn machen, wenn der Button bei einer Kompositionsbeziehung das Option Declare des Container-Objekts (=Maske) übernähme.
{ und übernähme steht hier FREAKIN' NOT!!! für eine Vererbung.
A Button IS NOT A Form.
Vielmehr A Form HAS [0...n] Button
Die Button stehen zwar mit der Maske in Beziehung, es ist aber keine Vererbungsbeziehung.
Übernhemen heisst, dass das Property optionDeclare in den Button in Abhängigkeit von dem Property optionDeclare der Form gesetzt wird.
In OO wird das so gemacht (und kommt mir nicht mit Mehrfachvererbung. Das gilt mittlerweile als über-komplexes feature:

--- Code: ---class Form {
private optionDeclare;
private List buttons = new ArrayList();

  public setOptionDeclare (boolean val) {
        // abhängige Objekte manipulieren:
         Iterator it = buttons.iterator();
         while (it.hasNext()) {
              (Button) it.next()).setOptionDeclare(val);
             }
         optionDeclare = val;
   }
 [..]
}

Button {
 [...]
 private boolean optionDeclare;
  public setOptionDeclare (boolean val) { optionDeclare = val;}
[..]
}

--- Ende Code ---
}

Sobald der Code in eine Skriptlib ausgelagert wird, sieht es natürlich ganz anders aus.
Dann haben wir nämlich eine Aggregationsbeziehung. Potentiell oder real verwenden mehrere Komponenten den Code der gleichen Skriptlib. Dieses Code-Objekt ist nicht mehr einem eindeutigen Container-Objekt zugeordnet.

Ähnliches Beispiel aus CAD-mässiger Anwendung in Fowler, UML-Destilled:
Ein Polygon hat mehrere Punkt Objekte und mit der Umrandung ist ein Stil-Objket verbunden (gepunktete Linie, durchgezogene Linie, etc.).

Die Punkte haben eine Komposition-Beziehung zum Polygon (wie Button code nicht-in-ScriptLib).
Wenn das Polygon gelöscht wird, werden auch die Punkt-Objekte gelöscht.
Der Stil der Umrandung hat eine Aggregations-Beziehung zum Polygon. Ein Stil Objekt wird ja in aller Regel so gestaltet, dass er von mehreren Polygon-Objekten verwendet werden kann (wie code in ScriptLib). D.h. wenn das Polygon gelöscht wird, wird das Stil-Objekt nicht gelöscht.



--- Code: ---// beginner - intermediate level code, d.h. newbies verwirrt das :-)
class Polygon {
  private ArrayList points(x, y); // die Menge an individuellen Punkten wird gelöscht, wenn Polygon gelöscht wird
  private Style style;           /* Hier: Kopien von dem gleichen Style Objekt werden von mehreren Objekten benutzt. Nicht an Lebenszyklus Polygon gebunden */

   public void addPoint(int pos, int x, int y) {
        // das Polygon ist selbst Creator dieses Objekts. Hinweis auf Composition Beziehung
        Point point = new Point (x, y);
         points.add(pos, point);
     }
     
      public void setStyle(String nameOfStyle) {
           /* das Polygon holt sich Objekt von externen Factory, wo diese unabhängig erzeugt und möglicherweise gecached, von mehreren Objekten gleichzeitig verwendet wird. Hinweis auf Aggregation */
           style = StyleFactory.getInstance().create(nameOfStyle);
      }
}

class Point {
       private int x;
      private int y;
       public Point (int x, int y) {
         this.x = x;
         this.y = y;
       }
        public void getX() {
           return x;
         }
         public void getY() {
            return y;
         }
}
class StyleFactory {
/* implementiert als SINGLETON (es gibt in der Anwendung immer genau 1 StyleFactory-Objekt, */
    private static StyleFactory instance = new StyleFactory();
    private HashMap cache;
    private Style defaultStyle; // speziell definierter Style, der benutzt wird, wenn Factory nicht weiterweiss. 

// implementiere Singleton Pattern
public static StyleFactory getInstance() {
       return instance;
}   
// constructor
    private StyleFactory() {
     cache = new HashMap();
      defaultStyle = readSomeDatabaseToLookWhatsDefaultStyle

}

    public Style create (String nameOfStyle) throws StyleOfCacheNotFoundException {
         // lookup cache für entsprechende Kopie
        Style style = cache.get(nameOfStyle);
        if (style==null) {
         try {
          // NEU. Waren größere Fehler
            style = lookInDatabaseForDefinitionForThisTypeOfNameOfStyleAndCreateIt(nameOfStyle);
            cache.put(nameOfStyle, style); // style in cache tun
        } catch (StyleOfCacheNotFoundException e) {
             // Programmierer soll sich was gutes einfallen lassen.
            // z.B.:
            tellUserThatStyleWithThisNameCannotBeFound();
           style = defaultStyle;
            e.printStackTrace();
        }
        return style;
    }

--- Ende Code ---

Bei diesem Selbstversuch, wie ich das implementieren würde, ist mir etwas interessantes aufgefallen:
Von einer reinen Code-Perspektive her würden alle Polygone ein eigene Kopie von Style Objekt verwenden.
Aus einer Design-Perspektive heraus ist es jedoch Aggregation. Die eigentlich kostspielige Operation bei der Erzeugung der Style-Objekte ist nämlich:

--- Code: ---lookInDatabaseForDefinitionForThisTypeOfNameOfStyleAndCreateIt();

--- Ende Code ---

Wenn ein Objekt erstmal in der cache-HashMap liegt, ist es nämlich wesentlich ressourcenschonender, sich eine Kopie zu besorgen als wenn diese neu erzeugt werden müsste.
Somit kann man davon sprechen, dass die Style Objekte von verschiedenen Polygonen wiederverwendet werden.
Es ist aber - wie vieles in OO - ein bischen unscharf, nicht-trivial und komplex.

UML Symbole:
Aggregation: nicht ausgefüllte Raute.
Komposition: ausgefüllte Raute.

Die Unterscheidung zwischen Aggregation und Komposition wird oft als nicht so praxisrelevant dargestellt. In diesem Fall (Maske - code hinter Button - code referenziert aus ScriptLib) macht er aber Sinn.

Gruß Axel

---------------------------------
* es gibt 3 Arten von grundlegenden Beziehungen zwischen Objekten/Interfaces
is a: Vererbung. In Java realisiert durch extends
is like a: Interface Implementierung. In Java realisiert durch implements
has a: Assoziation. In Java realisiert durch Referenz auf anderes Objekt

Vlissides, Johnson, etc., Design Patterns von 1995 bedeutete wohl einen Paradigmenwechsel für OO, der u.a. auch darin besteht, dass es die Bedeutung von "is like a" und "has a" Beziehungen gegenüber Vererbung betonte. Jeder gute Java/C++/C#/Smalltalk Programmierer hat das im Kopf. Aber das nur am Rande.
Viele newbies (mein jetzt nicht dich, Jens) haben, wenn sie an OO denken zu sehr Vererbung im Kopf. Vererbung ist aber nicht der wichtigste Punkt.

Semeaphoros:
Danke Axel für diese theoretische Untermauerung, und ich stimme Dir zu, das "Mutter" in dem Kontext nicht der richtige, aber ein bildlich sehr einprägsamer Ausdruck war.

Marinero Atlántico:
 ;D
Warum ist hier eigentlich keinen aufgefallen, dass mein HashMap-cache nichts cached.
Werds korrigieren  :P ;D

Navigation

[0] Themen-Index

[#] Nächste Seite

[*] Vorherige Sete

Zur normalen Ansicht wechseln