Delphi Object Pascal

2.2. Delphi Object Pascal

2.2.1. Object Oriented Programming

Sejak pertama komputer ditemukan sampai dengan sekarang telah terjadi evolusi terhadap bahasa pemrograman. Penggerak evolusinya adalah keinginan untuk mendapatkan sebanyak mungkin dengan usaha dan sumber daya yang sedikit mungkin (prinsip ekonomi). Pada awalnya, pemrograman dilakukan dengan memasukkan urutan perintah bahasa mesin, yang kemudian berubah dengan munculnya bahasa pemrograman tingkat rendah, seperti BASIC. Pada tahap ini, antara data dan perintah tidak dipisahkan secara tegas. Selanjutnya program terpecah menjadi subprogram, dan data dipisah dari program.

Akhirnya program dipecah menjadi objek, di mana dalam objek terdapat subprogram dan data, yang mempunyai keterkaitan satu dengan lainnya. Konsepinilah yang akhirnya berkembang dan disebut dengak konsep Object Oriented Programming.

Keuntungan bahasa pemrograman OOP dibandingkan dengan bahasa pemrograman pendahulunya adalah :

 Lebih terstruktur.  Lebih modular, serta mudah digunakan kembali (reusable).  Lebih tahan terhadap perubahan.  Lebih mudah dikembangkan.  Lebih “alami”.

Ciri‐ ciri dasar dari Object Oriented Programming (OOP) adalah : Classes (Kelas Objek) adalah definisi data dan fungsi/prosedur yang terbungkus secara abstrak. Konsep

pendefinisian kelas ini biasanya disebut sebagai Data Abstraction (Abstraksi Data). Definisi kelas ini biasanya akan menjadi kerangka modularitas program.

Encapsulation (Pembungkusan) adalah membungkus/menyembunyikan bagian‐ bagian tertentu dari program, sehingga pemakai objek tidak perlu tahu bagian internal dari objek tersebut.

Inheritance (Pewarisan) adalah hubungan antar‐ object yang memungkinkan disusunnya hirarki object. Setiap objek anak akan mempunyai sifat dari moyangnya.

Polymorphism (Kebanyakrupaan), adalah kemampuan mengungkapkan/melakukan hal yang sama dengan cara yang berbeda.

Page 51

Keempat hal di atas adalah syarat agar sebuah bahasa pemrograman disebut sebagai OOP. Bila sebuah bahasa tidak mempunyai fitur Inheritance dan Polymorphism tetapi mempunyai pendefinisian Classes saja, maka bahasa pemrograman tersebut biasanya disebut sebagai Object‐ Base.

2.2.2. Class dan Instance

Class adalah kelas, cetakan, jenis, atau abstraksi dari objek. Sedangkan Instance adalah contoh nyata objek dari kelas tertentu. Atribut adalah data yang dimiliki oleh objek. Atribut sering juga disebut sebagai field atau property dari objek. Methods adalah function atau procedure yang dimiliki oleh objek tersebut.

Berikut ini adalah beberapa contoh dari class dan instance.  Manusia adalah kelas.

 Si Fulan adalah contoh nyata dari kelas manusia.  Tinggi badan, warna kulit, pekerjaan, adalah atribut dari kelas manusia.  Kucing adalah kelas.  Si Meong adalah contoh nyata dari kelas kucing.

Dalam konteks pemrograman, kelas adalah tipe data, sedangkan contoh nyata adalah tempat dalam memori di mana objek dibuat. Pada contoh berikut ini kita mendefinisikan kelas sebagai tipe objek yang biasanya definisi kelas diletakkan pada bagian interface. Tetapi bisa juga diletakkan pada bagian implementation.

type

MyClass = class

private

MyData1 : Integer; MyData2 : Integer;

public

function GetMyData1 : Integer; function GetMyData2 : Integer; function GetMyData3 : Integer;

end;

Setiap method yang didefinisikan dalam kelas harus didefinisikan implementasinya pada bagian implementation.

function MyClass.GetMyData1 : Integer;

begin

result := MyData1;

end;

function MyClass.GetMyData2 : Integer;

begin

result := MyData1;

end;

function MyClass.GetMyData3 : Integer;

begin

result := 1;

end;

Page 52

Pada bagian lain dari program (bisa unit lain), kita dapat mendefinisikan variabel dengan tipe objek yang sudah kita deklarasikan. Dalam Delphi, variabel bertipe objek merupakan variabel bertipe pointer. Yang disebut sebagai instance dari objek adalah tempat di memory yang ditunjuk oleh variabel pointer tersebut. Akan tetapi, untuk menyederhanakan pembicaraan, biasanya variabel tersebut yang dinyatakan sebagai instance dari objek.

// di tempat tertentu dalam program var

Obj : MyClass;

begin

Obj := MyClass.Create; X := Obj.GetMyData1;

end;

Dalam contoh di atas, MyClass adalah kelas, sedangkan instance‐ nya berada dalam memori yang ditunjuk oleh variabel Obj (dengan singkat dapat dikatakan bahwa Obj adalah instance dari MyClass). MyData1 dan MyData2 adalah atribut dari kelas MyClass,sedangkan GetMyData1 dan GetMyData2 adalah methods dari MyClass.

2.2.3. Property dan Field

Objek mempunyai atribut, yaitu data dari objek tersebut. Dalam Delphi, atribut objek ada dua macam, yaitu field dan property. Field adalah variabel yang dimiliki oleh objek, sedangkan property adalah atribut objek yang didefinisikan dengan kata kunci property. Untuk lebih jelasnya, perhatikan contoh di bawah ini.

TMyObject = class

private

FMyData : Integer;

public

property MyData : Integer read FMyData write FMyData;

end;

Pada contoh di atas, FMyData adalah field, sedangkan MyData adalah property. Ketika kita mendefinisikan property, kita dapat menentukan bagaimana data dibaca (getter) dan

bagaimana data dituliskan ke dalam objek (setter). Getter kita deklarasikan dengan kata kunci read, sedangkan setter dengan kata kunci write. Getter bisa langsung berupa field atau menggunakan function tertentu. Setter‐ pun demikian, bisa langsung berupa field atau menggunakan procedure tertentu.

TMyObject = class

private

function GetMyData : Integer; procedure SetMyData (const Value : Integer);

public

property MyData : Integer read GetMyData write SetMyData;

end;

Page 53

2.2.4. Property Berindeks

Kita dapat mendefinisikan property yang mempunyai indeks untuk mengaksesnya. Sebagai contoh property pages pada objek PageControl yang bertipe TTabSheet, kita dapat mengaksesnya menggunakan indeks, seperti pada contoh berikut.

PageControl1.Page[ 0].Caption := ‘Test’;

Untuk mendefinisikan property di atas, kita dapat menggunakan property yang mempunyai indeks yang dideklarasikan dalam kurung kotak. Pada property jenis ini, kita harus mendefinisikan getter dan setter dengan function dan procedure. Kita dapat menggunakan tipe ordinal (integer dan sebangsanya, character, atau enumerated), serta kita juga dapat menggunakan string sebagai index. Untuk lebih jelasnya, perhatikan contoh berikut ini.

type

TMySound = (tsClick, tsClack, TsClock) ; TMyObject = class

private

function GetMySoundStr (idx : TMySound) : string ; function GetTMyData (idx : string) : Integer ; function GetTMyIndex (idx : Integer) : string ; procedure SetMySoundStr (idx : TMySound ; const Value : string) ; procedure SetTMyData (idx : string ; const Value : Integer) ; procedure SetTMyIndex (idx : Integer ; const Value : string) ;

public

property MySoundStr [ idx : TMySound] : string read GetMySoundStr write SetMySoundStr ; property MyData [ idx : string] : Integer read GetTMyData write SetTMyData ; property MyIndex [ idx : Integer] : string read Get TMyIndex write SetTMyIndex default ;

end; Default pada Property Berindeks

Pada contoh di atas, kita menggunakan directive default pada property MyIndex. Hal ini, akan memungkinkan kita menyingkat akses ke field tersebut langsung dari variabel objek yang bertipe TMyObject, maka tanpa harus menggunakan x.MyIndex[0], kita dapat langsung menggunakan x[0].

Hal ini pulalah yang memungkinkan kita mengakses ListBox1.Items[i], meskipun Items bukan property berindeks tetapi property dengan tipe TStrings. Tetapi karena property Strings dari TStrings merupakan default, maka ListBox1.Items[i] sama dengan ListBox1.Items.Strings[i].

Catatan penting di sini adalah untuk direktif default pada property bertipe ordinal atau set (dan tidak berindeks). Direktif ini disebut storage specifiers, dan termasuk didalamnya adalah stored dan nodedefault. Storage specifiers tidak berkaitan dengan perilaku program (bukan nilai default objek ketika di‐ create) tetapi hanya berkaitan dengan penyimpanan nilai property ini pada storage, dan hanya untuk published property. Bila nilai property sama dengan nilai default yang disebutkan, maka property tidak disimpan dalam storage.

Page 54

2.2.5. Kelas TObject dan Variabel bertipe Object

Kelas TObject adalah kelas yang mempunyai posisi tertinggi dalam struktur hirarki objek dalam Delphi. Semua kelas adalah turunan dari TObject. Ketika kita hanya mendefinisikan sebuah objek tanpa diturunkan dari kelas apa pun, secara otomatis Delphi akan menurunkan kelas ini dari TObject.

type

MyClass = class

private

MyData1: Integer; MyData2: Integer;

public

function GetMyData1: Integer; function GetMyData2: Integer; function GetMyData3: Integer;

end;

Pada contoh di atas, MyClass tidak diturunkan dari objek apa pun. Secara otomatis kelas MyClass diturunkan dari TObject.

Semua variabel bertipe TObject maupun turunannya, adalah variabel pointer. Oleh sebab itu, sebelum variabel tersebut dapat dipakai harus disiapkan memory untuk objek yang dimaksud dengan cara memanggil constructor‐ nya(biasanya constructor bernama Create). Selain itu, seperti halnya sifat variabel pointer biasa, assignment antara dua variabel pointer tidak akan meng‐ copy objek, tetapi kedua variabel akan menunjuk ke instance yang sama.

var

Obj1, Obj2: MyClass;

begin

Obj1 := MyClass.Create; Obj2 := Obj1; Obj1.MyData1 := x;

end;

2.2.6. Method

Method adalah function atau procedure yang dimiliki oleh objek. Method didefinisikan sebagai member dari suatu kelas. Cara pendefinisian dan perilakunya sangat mirip dengan function atau procedure biasa. Perbedaannya adalah pada bagian implementasi dari method kita harus memberikan qualifier yang merupakan nama kelas. Perhatikan contoh definisi objek berikut ini.

TMyObject = class

public

procedure MyProc(x: Integer); function MyFunc(X : Double); Double;

end;

Kedua method yang mempunyai TMyObject harus kita implementasikan seperti pada contoh berikut ini. function TMyObject.MyFunc(X: Double): Double;

begin

Page 55 Page 55

end;

procedure TMyObject.MyProc(x: Integer);

begin

// do something

end;

Cara menggunakannya dapat dilakukan seperti contoh berikut ini.

Y := X.MyFunc(10);

Pada contoh di atas, X adalah instance dari TMyObject.

Constructor dan Destructor

Constructor dan destructor adalah method khusus dari objek yang akan dipanggil untuk membangun objek (constructor) dan menghancurkan objek (destructor). Meskipun tidak harus, sebaiknya nama constructor adalah create dan nama destructor adalah destroy.

Abstract Method dan Abstract Class

Abstract method adalah method yang tidak mempunyai implementasi. Abstract class adalah kelas yang mempunyai paling tidak satu abstract method. Abstract class murni adalah kelas yang seluruh method‐ nya abstrak dan tidak mempunyai definisi field. Untuk mendefinisikan abstract class dalam Delphi, kita tinggal menambahkan kata kunci abstract. Tetapi abstract method harus bersifat virtual, sehingga sebelum kita nyatakan sebagai abstract, sebuah method harus dinyatakan sebagai virtual terlebih dahulu seperti contoh di bawah ini.

TMyObject = class

public

function MyAbstFunc(X: Double) : Double; virtual; abstract;

end;

Class Method

Bila method biasa hanya dapat dipanggil dari instance object, class method adalah method yang dapat dipanggil langsung dari tipe kelasnya (tanpa perlu create objek). Cara mendefinisikannya adalah dengan menambahkan kata kunci class di depan method yang kita definisikan. Cara menggunakannya adalah dengan memanggil nama kelas diikuti nama class method‐ nya. Berikut ini adalah contoh penggunaannya.

TMyObject = class

public

class function Test : string;

end;

Adapun implementasi dari class method di atas terlihat dalam contoh di bawah ini. class function TMyObject.Test : string;

begin

result := ClassName;

end;

Page 56

Sedangkan cara menggunakannya sebagai berikut ini. procedure TForm1.ButtonClick(Sender : TObject);

begin

ShowMessage(TMyObject.Test);

end;

Dalam class method kita dapat memanggil constructor ataupun class method lain. Namun kita tidak dapat mengakses field, property, dan method biasa.

2.2.7. Encapsulation

Encapsulation adalah menyembunyikan bagian internal program sehingga secara alamiah tidak menjadi perhatian bagi pengguna objek tersebut. Bagian objek yang dapat dikenali oleh pihak luar biasanya adalah bagian publik, sedangkan bagian yang disembunyikan adalah bagian private. Delphi menyediakan 3 (tiga) buah direktif yang berkaitan dengan information hiding, yaitu private, protected, dan public. Selain itu, di tingkat yang setara, Delphi menyediakan direktif published untuk RTTI.

Gambar 3‐ 1. Encapsulation

Private

Direktif ini digunakan untuk mendefinisikan objek member (field, property, dan method) yang bersifat internal. Bila sebuah objek member bersifat private maka member ini hanya bisa diakses dari unit yang sama.

Public

Bila suatu objek member diinginkan agar dapat diakses dari unit lain, maka member ini harus didefinisikan sebagai public.

Protected

Protected berada di antara private dan public. Setiap member yang didefinisikan sebagai protected dapat diakses oleh modul manapun bila berada di unit yang sama (serupa dengan private). Tetapi protected member hanya dapat diakses oleh turunan objek bila berada di unit yang terpisah.

Page 57

Published

Direktif published digunakan untuk mendefinisikan bahwa property atau method akan mempunyai RTTI (run‐ time type information). Visibility‐ nya sama dengan public, yang berarti member yang bersifat published dapat diakses dari unit lain. Adapun RTTI menyebabkan property bisa muncul di Object Inspector. Property atau method bisa berada pada bagian published. Tetapi hanya field yang bertipe kelas atau interface saja yang dapat berada di bawah published.

2.2.7.1. Event

Dalam Delphi, event adalah property yang bertipe method dan mempunyai visibility published. Karena mempunyai visibility published, event mempunyai RTTI sehingga dapat muncul di Object Inspector. Sebagai property, kita dapat meng‐ assign event seperti halnya kita meng‐ assign property biasa, tentu saja dengan syarat tipenya kompatibel. Pada saat tertentu sesuai dengan kebutuhan program, property bertipe method ini akan dijalankan setelah diperiksa terlebih dahulu bahwa nilainya tidak nil. Delphi memanfaatkan teknik ini agar perilaku komponen bisa diintervensi oleh Software Engineer sebagai user komponen tersebut.

2.2.8. Inheritance

Dalam OOP, konsep inheritance dilakukan dengan generalisasi dan spesialisasi. Semua kemampuan yang dimiliki oleh suatu objek pasti dimiliki oleh turunan dari objek tersebut. Keuntungan penting lain dari adanya inheritance dalam OOP adalah kita bisa menambahkan kemampuan objek yang sudah tersedia tanpa mengubah kode objek tersebut. Dalam Delphi, setiap kita mendefinisikan objek baru, kita pasti menurunkannya dari objek lain, paling tidak dari TObject. Ini berarti kita sudah melakukan inheritance. Kita bisa melakukannya dengan membuat objek baru yang diturunkan dari objek yang sudah tersedia.

TMyObject = class (TLabel)

end;

Pada contoh di atas, TMyObject adalah turunan dari TLabel.

2.2.9. Polymorphism

Secara luas, polymorphism berarti kode yang sama dapat digunakan untuk kelas atau tipe data yang berbeda dengan hasil yang berbeda sesuai dengan kelas atau data yang ada. Dengan arti yang luas ini, operator tambah (+) juga mempunyai sifat polymorphism, karena dapat bekerja untuk integer, real, maupun string. Demikian juga overloading method, function, atau procedure mempunyai sifat polymorphism. Yang kita bahas di sini adalah polymorphism yang berkaitan dengan inheritance (subclassing), di mana sifat yang sudah terdefinisi pada nenek moyangnya dapat di‐ implementasi oleh objek turunannya dengan cara berbeda. Misalkan kita mempunyai objek TBentuk yang kita turunkan menjadi TKotak dan TEllipse. Pada objek TBentuk kita definisikan method Gambar. Untuk setiap turunan dari TBentuk, kita akan meng‐ implementasi method Gambar ini secara berbeda sesuai kebutuhan kita. Ketika kita mempunyai sekumpulan objek TBentuk, tanpa peduli objek tersebut adalah TKotak atau TEllipse, kita dapat memanggil method Gambar yang akan menampilkan hasil yang berbeda. Untuk lebih jelasnya perhatikan contoh berikut ini.

Page 58

Pertama kita akan mendefinisikan 3 (tiga) buah objek, yaitu TBentuk, TKotak, dan TEllipse. Dalam objek TBentuk kita definisikan method Gambar yang bersifat virtual.

TBentuk = class

private

FBound : TRect;

public

constructor Create(vBound : TRect); procedure Gambar (vCanvas : TCanvas) ; virtual;

end;

TKotak = class (TBentuk)

public

procedure Gambar(vCanvas : TCanvas) ; override;

end;

TEllipse = class (TBentuk)

public

procedure Gambar(vCanvas : TCanvas) ; override;

end;

Implementasi untuk constructor create dan method Gambar dari TBentuk sebagai berikut ini. { TBentuk }

constructor TBentuk.Create(vBound : TRect);

begin

FBound := vBound;

end;

procedure TBentuk.Gambar(vCanvas : TCanvas);

begin // Tidak melakukan apa-apa end;

Method Gambar dari TBentuk tidak melakukan apa‐ apa, karena bentuk memang tidak bisa digambar. Biasanya yang seperti ini dibuat menjadi abstract method.

Implementasi Gambar untuk TKotak dan TEllipse sebagai berikut ini. { TKotak }

procedure TKotak.Gambar(vCanvas : TCanvas);

begin

vCanvas.Rectangle(FBound);

end;

{ TEllipse } procedure TEllipse.Gambar(vCanvas : TCanvas);

begin

vCanvas.Ellipse(FBound);

end;

Page 59

Selanjutnya akan kita lihat bagaimana menggunakan TBentuk, TKotak, dan TEllipse. Pertama, kita definisikan sebuah array of TBentuk yang bisa kita letakkan di bagian interface.

var

FArrayBentuk : array of TBentuk;

Kemudian elemen‐ elemen array‐ nya kita create sebagai TKotak atau TEllipse pada secara random dengan FBound yang random juga. Kita perlu sebuah function yang bisa menghasilkan rectangle random. Untuk meng‐ inisialisasi dan membuang array kita gunakan masing‐ masing sebuah procedure.

function RandomRect(X, Y, W, H : Integer) : TRect; var vX, vY : Integer;

begin

vX := Random(X); vY := Random(Y); result := Rect(vX, vY, vX+Random(W), vY+Random(H));

end;

procedure InitArray(Count : Integer); var i : Integer;

vRect : TRect;

begin

SetLength(FArrayBentuk, Count); for i := 0 to Count-1 do begin

vRect := RandomRect(400, 500, 10, 20); if Random(2) = 1 then begin

FArrayBentuk[ i] := TKotak.Create(vRect);

end else begin

FArrayBentuk[ i] := TEllipse.Create(vRect);

end; end; end;

procedure RemoveArray; var i : Integer;

begin

for i := 0 to Length(FArrayBantuk)-1 do begin FArrayBentuk[ i] .Free;

end; end;

Procedure InitArray kita panggil pada bagian Initialization. Pada bagian finalization kita panggil RemoveArray.

Berikut ini adalah contoh penting untuk polymorphism‐ nya.

for i := 0 to Length(FArrayBentuk)-1 do begin FArrayBentuk[ i] .Gambar(PaintBox1.Canvas);

end;

Page 60

Pada potongan kode di atas, elemen FArrayBentuk adalah bertipe TBentuk. Tetapi pada saat di‐ create, objek‐ objek TBentuk tersebut bisa berupa TKotak atau TEllipse. Tetapi kode di atas tidak peduli apakah objek actual yang ditunjuk oleh elemen Array adalah TKotak atau TEllipse. Kode di atas masih bisa bekerja tanpa perubahan meskipun kita menurunkan lagi TBentuk menjadi TPolygon, TSegitiga, ataupun yang lainnya.