Özet Sınıfların Kullanımı - abstract [14]

Bazen, şöyle bir temel sınıf oluşturmak istersiniz: O sınıf sadece kendisinden türetilmiş sınıfların genelleştirilmiş bir şekli olmalı, detaylar her bir türetilmiş sınıf tarafından doldurulmalıdır. Bu tür bi sınıf, türetilmiş sınıfların uygulamaları gereken metotların özünü belirler, fakat bu metotlardan biri ya da daha fazlasi için kendisi bir uygulama sağlamaz. Temel sınıf, anlamlı bir metot uygulaması oluşturamadığı zaman böyle bir durumla karşılaşılabilir. TwoDShape'in yukarıdaki örnekte(konu [13]) kullanılan versiyonunda bu tür bir durum söz konusudur. area()'nın tanımı yalnızca bir yer belirteci olmaktan ibarettir. area(), hiçbir nesne tipinin alanını hesaplayıp, ekranda göstermez.

Kendi sınıf kütüphanelerinizi oluşturdukça göreceksiniz ki, bir metodun kendi temel sınıfı kapsamında anlamlı bir tanımının olmaması yaygın bir kullanım değildir. Bu durumu iki şekilde kontrol altına alınabilir. Birincisi, önceki örnekte gösterildiği gibi metodun bir uyarı mesajı vermesi yeterlidir. Bu yöntem belirli durumlarda -örneğin hata ayıklama sırasında- yararlı olsa da bu yöntemi uygulamak genellikle uygun değildir. Türetilmiş sınıfın bir anlam taşıması için türetilmiş sınıf tarafından devre dışı bırakılması gereken metotlara sahip olabilirsiniz. Triangle sınıfını ele aldğımız zaman area() tanımlanmazsa bu sınıfın bir anlamı kalmaz. Bu durumda, türetilmiş sınıfın gerçekten gerekli metotların tümünü devre dışı bırakmasını garanti edecek bir çözüme ihtiyacınız olur. Bu probleme C#'ın getirdiği çözüm özet metot kullanımıdır.

Özet metot abstract tip niteleyicisi kullanılarak oluşturulur. Özet metodun gövdesi yoktur; bu nedenle, özet metodlar temel sınıf tarafından gerçeklenmez. Yani, türetilmiş sınıf, özet sınıfı devre dışı bırakmalıdır -temel sınıf içinde tanımlanmış olan versiyonunu kullanamaz. özet metotlar otomatik olarak sanaldır ve virtual niteleyicisini kullanmaya gerek yoktur. Aslında, virtual ve abstract niteleyicilerini birlikte kullanmak hatalıdır. Özet metotlar aşağıdaki gibi deklare edilir.

abstract tip-ismi(parametre-listesi);

Metot gövdesi mevcut değildir. abstract niteleyicisi yalnızca normal metotlarla kullanılabilir. static metotlara uygulanamaz. Özellikler de özet olabilir. Bir veya daha fazla özet metot içeren bir sınıf da özet olarak deklare edilmelidir. Bunun için class deklerasyonundan önce abstract belirleyicini kullanmalısınız. Özet bir sınıf komple bir uygulama tanımlamadığından dolayı, özet bir sınıfa ait nesneler mevcut olamaz. Böylece, new kullanılarak özet bir sınıfa ait bir nesne oluşturmaya çalışmak derleme sırasında hatayla karşılaşmaya neden olur.
Bir özet sınıf kalıtım yoluyla bir türetilmiş sınıfa aktarılınca, söz konusu türetilmiş sınıf temel sınıf içinde yer alan özet metotların tümünü uygulamak zorundadır. Eğer uygulamazsa, türetilmiş sınıf da ayrıca abstract olarak belirtilmelidir. Böylece; abstract niteliği, özet metotların tamamen uygulanana kadar kalıtım yoluyla aktarılır.
Özet sınıf kullanarak TwoDShape sınıfını geliştirebilirsiniz. Tanımlanmamış iki boyutlu bir şeklin alanını ifade etmek için, anlamlı bir kavram mevcut değildir. Bu nedenle, önceki programın aşağıdaki versiyonunda area(), TwoDShape içinde abstract olarak deklare edilmektedir. TwoDShape de abstract olarak deklare edilir. Bu, kuşkusuz, TwoDShape'ten türetilen tüm sınıfların area()'yı devre dışı bırakması gerektiği anlamına gelmektedir.

// ozet bir sinif olustur.
using System;

abstract class TwoDShape {
double pri_width; // private
double pri_height; // private
string pri_name; // private
// varsayilan yapilandirici.
public TwoDShape() {
width=height=0.0;
name="null";
}
//parametreli yailandirici.
public TwoDShape(double w, double h, string n) {
width=w;
height=h;
name=n;
}
//Esit width ve height degerlerine sahip bir nesne yapilandir
public TwoDShape(double x, string n) {
width=height=x;
name=n;
}
//Bir nesneden baska bir nesne yapilandir.
public TwoDShape(TwoDShape ob) {
width=ob.width;
height=ob.height;
name=ob.name;
}
//width, height ve name icin ozellikler
public double width {
get { return pri_width; }
set { pri_width=value; }
}
public double height {
get { return pri_height; }
set { pri_height=value; }
}
public string name {
get { return pri_name; }
set { pri_name=value; }
}
public void showDim() {
Console.WriteLine("width and height are " + width + " and " + height);
}
// artik area() ozettir.
public abstract double area();
}

//Ucgenler icin TwoDShape'ten turetilen bir sinif.
class Triangle : TwoDShape {
string style; // ozel
// varsayilan yapilandirici
public Triangle() {
style="null";
}
// Triangle için yapilandirici.
public Triangle(string s, double w, double h) : base(w, h, "triangle") {
style=s;
}
// ikizkenar bir ucgen yapilandir.
public Triangle(double x) : base(x, "triangle") {
style="isosceles";
}
//bir nesneden baska bir nesne yapilandir.
public Triangle(Triangle ob) : base(ob) {
style=ob.style;
}
//Triangle icin area()'yı devre disi birak.
public override double area() {
return width*height/2;
}
// ucgenin seklini goster.
public void showStyle() {
Console.WriteLine("Triangle is " + style);
}
}

//dikdortgenler icin TwoDShape'ten turetilmis bir sinif.
class Rectangle : TwoDShape {
//Rectangle icin yapilandirici
public Rectangle(double w, double h) : base(w, h, "rectangle"){
}
//bir kare yapilandir.
public Rectangle(double x) : base(x, "rectangle") {
}
//bir nesneden bir baska nesne yapilandir.
public Rectangle(Rectangle ob) : base(ob) {
}
//dikdortgen bir kareyse true dondur.
public bool isSquare() {
if(width==height) return true;
return false;
}
//Rectangle icin area()'yi devre disi birak.
public override double area() {
return width*height;
}
}

class AbsShape {
public static void Main() {
TwoDShape[] shapes=new TwoDShape[4];
shapes[0]=new Triangle("right", 8.0, 12.0);
shapes[1]=new Rectangle(10);
shapes[2]=new Rectangle(10, 4);
shapes[3]=new Triangle(7.0);
for (int i=0; i<4; i++) {
Console.WriteLine("object is " + shapes[i].name);
Console.WriteLine("Area is " + shapes[i].area());
Console.WriteLine();
}
}
}

Programdan görüldüğü üzere, tüm türetilmiş sınıfların area()'yı devre dışıbırakmaları gerekmektedir.(veya abstract olarak da deklare edilebilirler). Bunu kendi kendinize ispatlamanız için area()'yı devre dışı bırakmayan bir türetilmiş sınıf oluşturmayı deneyebilirsiniz.
Bu durumda derleyici hatasıyla karşılaşırsınız. Elbette, TwoDShape tipinde bir nesne referansı oluşturmak hala mümkündür. Programda da böyle yapılmıştır. Ancak, TwoDShape tipinde nesne deklare etmek artık mümkün değildir. Bundan dolayı, Main()'de shapes dizisi 4 elemandan oluşacak şekilde kısaltılmıştır ve genel bir TwoDShape nesnesi artık oluşturulmaz.
Bir diğer husus: Buna rağmen TwoDShape'in içinde showDim() metodunun yer aldğına ve abstract ile nitelenmediğine dikkat edin. Bir özet sınıf, türetilmiş bir sınıfın "olduğu gibi" kullanmakta serbest olduğu somut metodlar içerebilir. Bu, tamamen kabul edilebilir -hatta oldukça yaygın bir kullanımdır. Yalnızca abstract olarak deklare edilen sınıflar türetilmiş sınıflar tarafından devre dışı bırakılmalıdır.
Kaynak: Herbert Schildt
Herkes İçin C#

Hiç yorum yok:

Yorum Gönder