Adaptor-Pattern mit Ocaml's Module System (Re: [linux-l] Ocml vs. Java)
Oliver Bandel
oliver at first.in-berlin.de
Fr Sep 23 08:26:01 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.
>
[...]
> > BTW: Adaptor-Pattern ist auch sehr interessant.
> > Im Pather-Buch (Perl) haben die das ja auch mal vorgeführt.
> >
> > Nach o.g. Buche steht da unter Intent:
> > "Convert the interface of a class into another interface clients expect.
> > Adapter lets classes wpork together that couldn't otherwise because of
> > incompatible intefaces."
> >
> > Hmhh, mach' mir jetzt nicht die Mühe, den ganzen Kram zu lesen;
> > schaue mir im Panther-Buch die Grafik an und würde wieder sagen, daß OCaml's
> > Modulsystem einem hier hilft.
> > Ein Interface und mehrere spezialisierte Implementierungen. Das riehct nach
> > Anwendung von Funktoren.
>
> Nee, Funktoren helfen da nicht.
Och, vielleicht würden die da sogar helfen,
aber man braucht sie noch nicht einmal.
Das Modulsystem ganz einfach mit Structure/Signature und
Module types reicht schon aus.
> Es geht darum, dass die
> Implementierungen einfach mal andere Interfaces habe, d.h. die
> Klassen, Funktionen, etc. völlig anders heißen, vielleicht sogar
> die Art, wie diese Funktionen zusammenarbeiten, anders ist.
Es geht aus Sicht des Adaptors darum, EIN Interface für verschiedene
andere Sourcen zu haben, das einen Adapter darstellt.
Klinke <-> CINCH
Klinke <-> BNC
Klinke <-> Banane
alles Klinke, oder was? ;-)
OK, mal ne Klinke bauen:
>
> Und was du dann machst, ist auch klar: Du suchst dir ein eigenes
> Interface, und schreibst einen kleinen "Wrapper". Das ist auch in
> OO-Sprachen überhaupt kein Ding.
Selbst in OO-Sprachen geht das also. Donnerwetter. ;-)
Na, dann erübrigt sich das folgende ja fast... aber nun bringe ich das
noch zu Ende. :)
> Es ist mehr ein notwendiges Übel,
> und das Muster sagt nur, dass du's einfach machen sollst, statt deinen
> gesamten Code auf das fremde Interface umzumuddeln.
Eben.
Na, dann woll'n wa mal:
==================================================================================
(* ----------------------------------------------------------------- *)
(* 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 *)
(* ----------------------------------------------------------------- *)
module A_unified =
(struct
include A
let print = print_dieses
(* and more adapter code if necessary *)
end
:
sig
val print : unit -> unit
end)
module B_unified =
(struct
include B
let print = print_jenes
(* and more adapter code if necessary *)
end
:
sig
val print : unit -> unit
end)
module C_unified =
(struct
include C
let print = print_noch_eins
(* and more adapter code if necessary *)
end
:
sig
val print : unit -> unit
end)
(* ----------------------------------------------------------------- *)
(* Now: use the adaptees *)
(* ----------------------------------------------------------------- *)
let _ = A_unified.print();
B_unified.print();
C_unified.print()
==================================================================================
mal schauen, was das Interface des adaptor.ml ist:
------------------------------------------------------
first:/tmp oliver$ ocamlc -i adaptor.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 A_unified : sig val print : unit -> unit end
module B_unified : sig val print : unit -> unit end
module C_unified : sig val print : unit -> unit end
==================================================================================
Und ausgeführt:
---------------
===========================================
first:/tmp oliver$ ocaml adaptor.ml
Hallo, dies ist Variante A!
Hallo, dies ist Variante B!
Hallo, dies ist Variante C!
first:/tmp oliver$
===========================================
Wie man sieht sind die Module alle selben Typs.
Adaption gelungen. :)
Kein OO notwendig.
Design Pattern mit Modul System erschlagen.
Kein besonderer Aufwand.
Man kann sich übrigens viel Tipparbeit sparen (und auch
Fehler bei den Moduls-Dignature, wenn man module types
nutz.
Das kommt in einer anderen Mail, wo es um die Bridge geht. :)
Ciao,
Oliver
Mehr Informationen über die Mailingliste linux-l