Bridge-Pattern mit OCaml's Modul System (Re: [linux-l] Ocml vs. Java)

Oliver Bandel oliver at first.in-berlin.de
Fr Sep 23 08:48:12 CEST 2005


On Thu, Sep 22, 2005 at 05:07:06PM +0200, Volker Grabsch wrote:
> On Wed, Sep 21, 2005 at 11:49:05PM +0200, Oliver Bandel wrote:
> > OK, dann habe ich mich vielleicht ungünstig/mißverständlich ausgedrückt.
> > 
> > Eine Sprache nennt man funktional, wenn man Funktionen GENAUSO wie
> > andere Values behandeln kann. Tricksereien gelten nicht.
> 
[...]

> > > Es gibt nämlich trotzdem etliche Design-
> > > Patterns, gerade im GoF-Buch, die wirklich Software-Design betreffen,
> > > wo man wirklich in der Planung und dessen, was man implementiert,
> > > umdenken soll. Zum Beispiel geht es im Brücken-Muster um Sachen, die
> > > man eben nicht per Sprach-Feature erschlagen kann.
> > 
> > Kommt auf die gewählte Sprache und ihre Features drauf an. :)
> > 
> > Brücken-Muster soll wahrscheinlich das sein, was in "Design Patterns"
> > von Gamma/Helm/Johnson/Vlissides als Bridge bezeichnet wird.
> 
> Du kennst es ja! Ich nur hab die deutsche Übersetzung. Aber: Ja, genau
> davon rede ich.
> 
> > Unter "Intent" steht dort auf S. 151:
> > 
> >    "Decouple an abstraction from it's implementation so that the two
> >     can vary independently."
> > 
> > Also, wenn ich das jetzt richtig verstehe (kannst ja korriegieren, wenn
> > es nicht stimmt), geht es darum, Interface und Implementierung trennen zu können.
> > Hmhhh. Wenn ich IMplemetierung und Interface voneinander trennen sollte,
> > habe ich mehrere Module mit unterschiedlicher Implementierung und
> > oräge dort allen eine einzige Signatur auf.
> > Dann kann man den Code verändern, aber das Interface bleibt gleich.
> 
> Keine Ahnung, was das soll. Du hast eben nur triviales Zeug von dir
> gegeben,

Na, warte es ab.
Nun wird es gleich handfest: Beispielcode folgt einige Zeilen später... :)


> und offenbar das Kapitel gar nicht gelesen. Nichtmal die
> Kurzbeschreibung hast du verinnerlicht:
> 
> 	"... can vary /independently/."

Meinst Du also...


> 
> Es geht darum, was du machst, wenn es ein Interface gibt, viele
> Implementierungen, und dass einerseits neue Implementierungen
> hinzukommen (bzw. sich ändern), aber andererseits auch das Interface
> mit der Zeit immer mehr können muss.

Na eben.



> 
> Sicher kannst du jetzt dem Interface neue Klassen/Funktionen hinzufügen,
> und das in jeder einzelnen Implementierung entsprechen hinzu coden.
> Genau das soll aber verhindert werden. Die GoF-Lösung, also das
> Brückenmuster, will ich hier jetzt nicht weiter ausführen, aber wenn
> man seinen Code umwirft und diesen Emüfehlungen folgt, hat man pro
> neuem Interface nur *einmal* was zu tun, und pro neuer Implementierung
> ebenfalls. Der Aufwandt für beides bleibt also stets konstant, statt
> immer größer zu werden, je mehr das Projekt wächst.

Ja, na und?

Soll ich Dich mal zitiren, zum Beispiel mit
 "Keine Ahnung, was das soll. Du hast eben nur triviales Zeug von dir" ?!



Also, dann mal etwas Bridge spielen:


========================================================================


(* ----------------------------------------------------------------- *)
(* Third Party Modules or something you don't want to change anymore *)
(* ----------------------------------------------------------------- *)
module A = 
  struct
    let print_dieses () = print_endline "Hallo, dies ist Variante A!"
    let hide_me () = print_endline "Hide me!" (* not hidden yet *)
  end

module B = 
  struct
    let print_jenes () = print_endline "Hallo, dies ist Variante B!"
    let hide_me_too () = print_endline "Hide me!" (* not hidden yet *)
  end

module C = 
  struct
    let print_noch_eins () = print_endline "Hallo, dies ist Variante C!"
    let hide_me_please () = print_endline "Hide me!" (* not hidden yet *)
  end


(* ----------------------------------------------------------------- *)
(* Now do the adaption (now using "module type" to save keystrokes)  *)
(* ----------------------------------------------------------------- *)
module type Unified = sig val print: unit -> unit end

module A_unified =
  (struct
    include A
    let print = print_dieses
      (* and more adapter code if necessary *)
  end : Unified)

module B_unified =
  (struct
    include B
    let print = print_jenes
      (* and more adapter code if necessary *)
  end : Unified)

module C_unified =
  (struct
    include C
    let print = print_noch_eins
      (* and more adapter code if necessary *)
  end : Unified)


(* --------------------------------------------------------------- *)
(* Now using a different interface                                 *)
(* --------------------------------------------------------------- *)

module type ChangedInterface = sig val anderes_interface_for_printing: string -> unit end

module A_3 =
 (struct

   let anderes_interface_for_printing text =
      Printf.printf " :) %s :)\n" text;
      A_unified.print();
      print_endline "Siehste, geht doch! ...! :)"

     (* more of new interfacing stuff goes here  *)
   end 
     :
   ChangedInterface)



(* ----------------------------------------------------------------- *)
(* Now: use the adaptees                                             *)
(* ----------------------------------------------------------------- *)

let _ = A_unified.print();
        B_unified.print();
        C_unified.print();
        print_endline "-------------";
        A_3. anderes_interface_for_printing "Some text";
        print_endline "=============";

========================================================================




========================================================================
Nun mal schauen, wie das Interface von bridge.ml maussieht:
-----------------------------------------------------------
first:/tmp oliver$ ocamlc -i  bridge.ml 
module A : sig val print_dieses : unit -> unit val hide_me : unit -> unit end
module B :
  sig val print_jenes : unit -> unit val hide_me_too : unit -> unit end
module C :
  sig
    val print_noch_eins : unit -> unit
    val hide_me_please : unit -> unit
  end
module type Unified = sig val print : unit -> unit end
module A_unified : Unified
module B_unified : Unified
module C_unified : Unified
module type ChangedInterface =
  sig val anderes_interface_for_printing : string -> unit end
module A_3 : ChangedInterface
========================================================================

Man sieht also:
 ein paar Zeile Code und die Bridge ist fertig.

Nicht meine Mail war trivial, sondern die Aufgabenstellung
mit der Bridge.

Nun noch zeigen, daß der Code auch läuft:


========================================================================
first:/tmp oliver$ ocaml bridge.ml 
Hallo, dies ist Variante A!
Hallo, dies ist Variante B!
Hallo, dies ist Variante C!
-------------
 :) Some text :)
Hallo, dies ist Variante A!
Siehste, geht doch! ...! :)
=============
first:/tmp oliver$ 
========================================================================


Also: geht doch.

Was willst Du mir jetzt noch erzählen?

BTW: Gerade für SOLCHE Sachen ist eine rigide Typprüfung
     enorm wichtig. Aber das Thema hatten wir ja schon woanders. ;-)


> 
> 
> Übrigens stehe ich gerade auch an so einem Problem, aber es ist gerade
> so vertrakt, dass ich das Brückenmuster nicht anwenden kann. Jedenfalls
> nicht so, wie es sich die GoF gedacht haben. Aus Effizienz-Gründen ist
> die "Brücke" bei mir etwas komplexer, eine Art Meta-Typ-System. Blöd
> zu erklären, aber wenn ich's fertig habe, ist es auf jeden Fall sehr
> leicht anzuwenden.


Ich glaube Dir gerne, daß Du an einem solchen Problem stehst.
Und wenn Du weiterhin auf Deinem Standpunkt verharrst, daß
Du allein weise bist und daß alle anderen von Dir geholfen
werden müssen ;-) und Du nicht über den Python-Tellerrand schauen
magst, dann wird die Problemlösung noch eine Weile auf sich warten
lassen. :->



Ciao,
   Oliver

P.S.: Daß Du als Mathematker keine funktionalen Sprachen magst,
      ist schon seltsam. *kopfschüttel*
      Gerade als Mathematiker sollte man da einen Blick drauf werfen... 

-- 
   "Don't mind your makeup,
    you'd better make your mind up."
                              (Frank Zappa)



Mehr Informationen über die Mailingliste linux-l