Yksinkertaista moniperintää Rubyn ja Pythonin mixineillä
Moniperintään liittyy useita ongelmia, joiden vuoksi esimerkiksi Java ja monet muut ohjelmointikielet eivät tue sitä. Javassa käytetään interfaceja simuloimaan moniperintää. Interfaceissa ei voi kuitenkaan olla ohjelmakoodia, joten ohjelmoijan pitää itse toteuttaa kaikki interfaceen liittyvät toiminnot omassa luokassaan. Seurauksena on sitä ikävää turhaa bloattia, josta Java-ohjelmat ovat tunnettuja.
Rubyn mixinit
Rubyssa moniperintä on ratkaistu mixineillä, jotka ovat oikein kaunis ja yksinkertainen tapa lisätä valmiita toimintoja omiin luokkiin. Tämä on kätevää pitkälti sen vuoksi, että kielessä on dynaaminen tyypitys. Mixin on käytännössä valmiita apumetodeita sisältävä moduuli. Nämä apumetodit voi lisätä "lennossa" omaan olioonsa extend-kutsulla:
module Sayable def say puts @message end end class Hello def initialize @message = 'Hello, World' end end hello = Hello.new hello.extend Sayable hello.say
Jos apumetodit haluaa lisätä pysyvästi mukaan omaan luokkaansa, sen voi tehdä luokkamäärittelyssä include-kutsulla:
class Hello def initialize @message = 'Hello, World' end include Sayable end
Pythonin mixinit
Pythonissa on moniperintä, mutta sen käyttö saattaa olla tarpeettoman hankalaa omissa projekteissa. Esimerkiksi konstruktorien kutsuminen oikealla tavalla on hieman epäintuitiivista ja menee heti rikki, jos hierarkian yksikin luokka jättää kutsumatta super-konstruktoria.
Monessa tapauksessa voikin olla järkevämpää simuloida mixinejä käyttämällä moniperintää pelkkien apumetodien määrittelyyn. Tässä lähestymistavassa mixin-luokassa ei ole konstruktoria eikä omia instanssimuutujia. Se vain olettaa, että mixiniä käyttävässä luokassa tietyt instanssimuuttujat on jo määritelty:
class Sayable(object): def say(self): print(self.message) class Hello(Sayable): def __init__(self): self.message = 'Hello, World' hello = Hello() hello.say()
Oma Hello-luokka voi periytyä jostain muusta luokasta. Silloin ohjelmoijan pitää huomioida super-konstruktorin kutsuminen oman koodinsa osalta, mutta mixin-luokista ei tarvitse välittää:
class Sayable(object): def say(self): print(self.message) class ExampleBase(object): def __init__(self): pass class Hello(ExampleBase, Sayable): def __init__(self): super(Hello, self).__init__() self.message = 'Hello, World' hello = Hello() hello.say()
Tämä malli toimii parhaiten, jos isäntäluokka on aina ensimmäisenä perimäluettelossa, ja mixin-luokat tulevat sen jälkeen. Pythonin MRO (method resolution order) kulkee nimittäin vasemmalta oikealle, ja super-kutsut kohdistuvat ensimmäisenä vasemmanpuoleisimpaan isäntäluokkaan.
0 Comments
You can use Markdown to format your comment:
Separate paragraphs in your text with two newlines