Nem Osztály alapú

objektum-orientált programozás






Cserép Máté

2013. november 21.

Osztály alapú OOP

  • Objektumokat osztályokból példányosíthatunk

  • Új féle objektumhoz új osztály is szükséges

  • Öröklődés típusok között valósítható meg

  • Jellemzően statikus típusrendszer


Osztály centrikus nyelvek

Duck typing

"When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck." - James Whitcomb Riley

szemantikát nem a típusrendszer, hanem az adattagok és a metódusok határozzák meg.

Duck Typing: Python

class Duck:
    def quack(self):
        print("Quaaaaaack!")
 
class Person:
    def quack(self):
        print("The person imitates a duck.")
 
def in_the_forest(duck):
    duck.quack()
 
def game():
    donald = Duck()
    john = Person()
    in_the_forest(donald)
    in_the_forest(john)
game()

Duck typing: C#

public class Duck {
    public void Quack() {
	    Console.WriteLine("Quaaaaaack!");
    }
}

public class Person {
    public void Quack() {
	    Console.WriteLine("The person imitates a duck.");
    }
} 
class Program {
    private static void InTheForest(dynamic duck) {
	    duck.Quack();
    } 
    
    private static void Main() {
	    Duck donald = new Duck();
	    Person john = new Person();
	    InTheForest(donald);
	    InTheForest(john);
    }
} 

NEM OSZTÁLY ALAPÚ OOP

  • Az objektum fogalom köré épít mindent

  • Jellemzően dinamikus típusrendszer
    (Kivétel például: Omega)


Kérdések

  • Hogyan jönnek létre az objektumok?

  • Hogyan valósul meg a típushierarchia?

Nem osztály alapú OOP

Nincsenek osztályok, csak objektumok, ezek létrejöhetnek
a "semmiből" (ex nihilo) vagy klónozással.


JavaScript:

var jakab = { 
    surname: "Gipsz",
    firstname: "Jakab",
    fullname: function() {
        return this.firstname + " " + this.surname;
    }
};

var dezso = Object.create(jakab);
dezso.firstname = "Dezső";
dezso.middlename = "János";
dezso.fullname = function() {
    return this.firstname + " " + this.middlename + " " + this.surname;
}

Prototípus alapú OOP

  • Klónozáskor a forrás objektum a cél objektum prototípusa lesz

  • A prototípus (mintadarab) lekérdezhető, esetleg módosítható

  • Egy objektum a prototípusát kiterjesztheti és elfedheti

JavaScript:

var obj1 = { name: "object 1", one: 1, two: 2 };
var obj2 = { name: "object 2", three: 3 };
obj2.__proto__ = obj1;

var obj3 = Object.create(obj2);
obj3.name = "object 3";
obj3.four = 4;
obj3 = { name: "object 3", one: 1, two: 2, three: 3, four: 4 };

Klónozás

  • Delegálás alapú (teljes élettartamú megosztás)

  • Másolás / összefűzés alapú (létrehozáskori megosztás)

Dinamikus kötés

  • A legspeciálisabb leszármazottól
    a mintapéldányok irányába

  • A legáltalánosabb prototípustól
    a leszármazottak irányába



Jellemzően a felfele irányt alkalmazzuk

Ellenpélda?

bETA

employee:
(# 
    computeSalary:< 
	    (# salary: @integer 
	    do noOfHours*80->salary; inner; 0->totalHours 
	    exit salary
	    #)
#); 
worker: employee
(# 
    computeSalary::< (# do seniority*4+salary->salary; inner #)
#); 
salesman: employee
(# 
    computeSalary::<
    (# 
        do noOfSoldUnits*6+salary ->salary;
            0 ->noOfSoldUnits; 
            inner
    #)
#) 

Történelem

  • Smalltalk: prototype design pattern

  • Self: az első prototípus alapú objektum-orientált nyelv

  • Törekvő népszerűség:
    • ECMAScript: JavaScript, JScript, ActionScript
    • Io, Lua, stb.

  • Kiterjesztő modul által támogatja:
    • Perl, Python, R, stb.

Self

Az adattagok és a metódusok is egyaránt ún. slot-ok

Másolás alapú klónozás, dinamikus típus

jakab = (|
    name = 'Gipsz Jakab'.
    uni = 'ELTE'.
|)
elek = jakab copy.
elek name: 'Remek Elek'.

Leszármazott vezérelt öröklődés

traits student = (|
    show = name println uni println.
|)
jakab = (|
    parent* = traits student.
    name = 'Gipsz Jakab'.
    uni = 'ELTE'.
|)
jakab show

Perl

Class::Prototyped: a Self által lefektetett modellre épül
my $obj1 = Class::Prototyped->new(
    one  => 1,
    sub1 => sub { print "This is sub1 in obj1" },
    sub2 => sub { print "This is sub2 in obj1" }
);
my $obj2 = Class::Prototyped->new(
    'parent*' => $obj1,
    two       => 2,
    sub2      => sub { print "This is sub2 in obj2" }
);

$obj2->sub1; # This is sub1 in obj1
$obj2->sub2; # This is sub2 in obj2 
my $mirror = $obj2->reflect();
$mirror->addSlots(
    sub1 => sub { print "This is sub1 in obj2" });
$mirror->deleteSlot("sub2");

$obj2->sub1; # This is sub1 in obj2
$obj2->sub2; # This is sub2 in obj1

Io

Nincsen ex nihilo objektum létrehozás, kizárólag klónozás
Point := Object clone do(
    x := 0
    y := 0
) 
Az objektum prototípusait egy protos elnevezésű lista tárolja
a := Point clone
b := Point clone
a x = 5
a x println                           // 5
b x println                           // 0
a protos first == Point               // true
b protos first protos first == Object // true
Delegálás alapú klónozás, copy-on-write technika
Leszármazott vezérelt öröklődés, többszörös is lehetséges

JavaScript

Objektum létrehozás: literál, klónozás vagy konstruktor

function Person(surname, firstname) {
    this.surname = surname;
    this.firstname = firstname;
    this.fullname = function() {
        return this.firstname + " " + this.surname;
    }
}

function Student(surname, firstname, neptun) {
    this.surname = surname;
    this.firstname = firstname;
    this.neptun = neptun;
}
Student.prototype = new Person();
var jakab = new Person("Gipsz", "Jakab");
var tamas = new Student("Tanulo", "Tamas", "JUH8RK");
document.writeln(tamas.fullname()); 
tamas.__proto__ == Student.prototype;          // true
jakab.__proto__ == tamas.__proto__.__proto__;  // true

JavaScript

Valójában nincs ex nihilo objektum létrehozás, csak klónozás

var obj = {};
obj.__proto__;           // object
obj.__proto__.__proto__; // null 
var obj = new Object();
obj.__proto__;           // object
obj.__proto__.__proto__; // null 

A konstruktor művelet is csak klónozás végső soron

function Person(surname, firstname) {
    this.surname = surname;
    this.firstname = firstname;
    this.fullname = function() {
        return this.firstname + " " + this.surname;
    }
}
Person.prototype = new Object(); 


JavaScript

"Prototípus konstruktorhívás":

function Person(surname, firstname) {
    this.surname = surname;
    this.firstname = firstname;
    this.fullname = function() {
        return this.firstname + " " + this.surname;
    }
}
Person.prototype = {
    surname: null,
    firstname: null,
    constructor: Person
};
function Student(surname, firstname, neptun) {
    this.__proto__.constructor.call(this, surname, firstname);
    this.neptun = neptun;
}
Student.prototype = new Person(); 
var tamas = new Student("Tanulo", "Tamas", "JUH8RK"); 

JavaScript

Delegálás alapú klónozás, leszármazott  vezérelt öröklődés

Dinamikus típusrendszer, a prototípus lista is dinamikus

var fac = {
    calculate: function() { /* ... */ }
};
  
var fib = {
    calculate: function() { /* ... */ }
};
  
var exec = {};
exec.__proto__ = fac;
document.writeln(exec.calculate());

exec.__proto__ = fib;
document.writeln(exec.calculate()); 


Dinamikus öröklődés

JavaScript

Kompatibilitási problémák


  • obj.__proto__
    • nem szabványos
    • IE nem támogatja
    • nem mindig írható

  • Object.getPrototypeOf(obj)
    • ECMAScript5 szabvány része
    • Opera nem támogatja, IE csak a 9. verziótól
    • csak olvasásra alkalmas

További ECMASCript nyelvek

  • JScript: a JavaScripthez nagyon hasonlóan

  • ActionScript:
    • 1.0: a JavaScripthez hasonló prototípus alapú objektum orientált modell

    • 2.0: bevezeti az osztály fogalmát, de csak nyelvi elemként, valójában csak objektumok vannak

    • 3.0: tényleges osztályok és osztályok közötti öröklődés.
      De: az osztályok rendelkeznek egy prototípus objektummal, a leszármazás a prototípus láncot is építi.

Lua

Az egyetlen összetett adattípus a tábla
Ezzel modellezhető a prototípus alapú objektum modell
Account = { }
function Account:new (name, value = 0)
	local object = {
		owner = name,
		balance = value
	}
	setmetatable(object, { __index = Account })
	return object
end
function Account.deposit (self, value)
	self.balance = self.balance + value
end
function Account:withdraw (value)
	self.balance = self.balance - value
end
acc = Account:new("Gipsz Jakab");
acc.deposit(acc, 100000);
acc:withdraw(20000); 



Vége

Nem osztály alapú objektum-orientált programozás

By Cserép Máté

Nem osztály alapú objektum-orientált programozás

  • 510