Hiç Bilmeyenler İçin Nesne Yönelimli Programlamaya Giriş-4

Bu yazı daha önce yazdığım Hiç Bilmeyenler İçin Nesne Yönelimli Programlamaya Giriş-3 yazısının devamıdır. Önce onu okumanızı öneririm.

Bir önceki iki yazıda şu soruları sormuş ve kısmen cevap vermiştik:

  1. Eklemek istediğimiz başlık sözlükte yoksa ve çağırdıysak bu sorunu bildirim göstermeden nasıl hallederiz?
  2. Başlık zaten varsa ve değiştirmek istemiyorsak, aynı başlığa yeni bir açıklama değerini nasıl ekleriz?
  3. Bir başlığı silmek ya da düzenlemek istediğimizde ve başlıkta birden fazla açıklama varsa, tüm açıklamalara mı etki edeceğiz yoksa sadece birine mi?
  4. Bir başlığa, tarih bilgisini nasıl girebiliriz? Bu tarih bilgisine dayanarak nasıl sıralama işlemi yapabiliriz?
  5. Arama, filtreleme işlerini nasıl yapacağız?

Önce, bir önceki yazıda spagetti usulüyle bir takım değişiklikler yapmıştık. Bu değişiklikleri Dictionary.php dosyasındaki sınıfa taşıyarak işe başlayabiliriz.

Dictionary.php dosyamızın içine şu metodu ekleyelim:

public function getEntry(string $key): string
{
if (array_key_exists($key, $this->entries)) {
return $this->entries[$key];
}
}

2. soruyla devam edelim. Aynı başlığa birden fazla değer eklemek istediğimizde ne yapmamız gerek? Burada Dictionary sınıfımızın davranışını gözle görülür şekilde değiştirmemiz gerekecek. Yani, Dictionary sınıfı, artık kendisinden bir başlık talep ettiğimizde metin yani string değeri yerine bize bir dizi değeri döndürmeli.

Sınıfları görevlerine göre parçalamak

Dikkat: Dictionary sınıfının sorumlulukları artıyor! Sözlük yani Dictionary sınıfı sadece verilen başlıklara karşılık açıklamaları yerine getirmek sorumluluğuna sahipti. Şimdi bir sözlük girdisinin nasıl yönetileceğine de el atmaya başladı. Bu nedenle, sınıflarımızı temiz ve düzenli tutmak istiyorsak, tek sorumluluk yani single responsibility prensibine göre sınıfımızı parçalamamız gerekiyor. Henüz tasarım ve prototip aşamasında olduğumuzdan, sınıfımızın davranışını, arayüzünü ve kodlarını istediğimiz gibi değiştirebiliriz. Ancak örneğin milyonlarca kullanıcısı olan, koda kafamıza göre müdahele etmemizin kabusa yolaçacağı durumlar profesyonel hayatımızda zırt pırt karşımıza çıkacak. İkinci aklımızda tutmamız gerek prensip Open-Closed yani Açık-Kapalı prensibi. Bu prensibe göre,

Sınıflar değişime kapalı, gelişime açık olmalıdırlar.

Üstte bahsettiğim sorunu çözmenin, farklı yöntemleri mevcut ki bu yöntemleri kullanmamız sayesinde Amerikayı yeniden keşfetmemize veya tekerleği bir daha icat etmemize gerek kalmasın. Bu prensibi nasıl kullanacağımıza daha sonra detaylıca değineceğim. Şimdilik sınıfımızı parçalamakla işe başlayalım. Sözlük sınıfımızı parçalayıp yeni bir girdi sınıfı hazırlayacağız. Burada özellikle dikkat etmemiz gerek nokta, sınıfların birbirlerinden bağımsız, tek başına yaşayabilen canlılar gibi olmaları. Şimdi tekrar sınıflarımızın sorumluluklarını güncelleyelim.

Programımız lego gibi sökülüp takılabilen parçalardan oluşmalı

Sözlük sınıfının sorumlulukları

  1. Farklı başlıklara sahip olan sözlükler yaratmak, başlığı güncelleyip değiştirebilmek.
  2. Arama, sıralama, güncelleme, filtreleme işlerini yapmak.
  3. Sıralı olan nesne verisini, örneğin metin, word veya json formatında kullanıcıya göndermek.
  4. Bir girdiği listeden silmek, yeni bir girdiyi listeye eklemek. Dikkat, girdiyi güncellemek, sözlük sınıfını alakadar etmiyor. Aynı başlıkta hali hazırda başka bir girdi listede mevcutsa, hata vermek. Çünkü girdi başlıkları benzersiz olacak. Bazı sözlüklerde aynı başlıkla farklı girdiler eklenebiliyor. Ancak bizim sözlüğümüzde girdiler 1. açıklama 2. açıklama diye ilerleyecekler.
Girdi Örneği

Girdi sınıfının sorumlulukları

  1. Yeni bir başlık ve açıklama ile bir girdi yaratmak.
  2. Girdinin başlığını ve açıklamalarını değiştirmek.
  3. Girdiye yeni açıklama girmek.
  4. Girdiyi silmek. Silerken açıklamalar dizisini boşaltmak. Eğer girdinin tüm açıklamaları silindiyse, girdinin kendisini silmek.
  5. Sırası bilinen açıklamayı silmek, değiştirmek.

Tembel yazılımcılar için arayüz yani interface kavramı

Daha önce arayüz kavramından, otomobil örneği ile bahsetmiştik. Arayüz sınıfımızın nasıl kullanıldığını dünyaya tanıtan bir programlama yapısı. Arayüzler, içi boş metodların bir listesinden başka bir şey değil aslında. Arayüzlerin içinde metodun kodundan ziyade metodun imzasını, yani aldığı parametreleri, paramtere tipini, döndüreceği değerin tipini tanımlıyoruz.

Bizi sadece dışarıdaki butonlar fln ilgilendiriyor, bu butonlarla cihazı kullanıyoruz. İçindeki elektronik hedelerle alakamız yok.

Arayüz tanımlamak aynı zamanda, kodun nasıl çalışacağını yazmaya girişmeden önce bize genel olarak program yapısını tasarlama fırsatı veriyor. Peki PHP’de arayüz nasıl tanımlanıyor? Öncelikle arayüz yazarken arayüz adı ve sonun Interface yazmayı alışkanlık haline getirelim. Böyle yapmak zorunlu değeil ama şıklık, düzenlilik açısından şart. Bunun gibi iyi pratiklere baştan sahip olmaya çalışırsanız, daha sonra sorun yaşamazsınız. Şimdi ilk arayüzümüzü yazmaya başlayalım.

Girdi Arayüzü yani EntryInterface

<?php

namespace
MidoriKocak;


interface EntryInterface
{
function setKey(string $key);
function getKey(): string;
function setValues(array $values);
function getValues(): array;
function getValue(int $order): string;
function setValue(int $order, string $newValue);
function addValue(string $value);
function deleteValue(int $order);
}

Tıpkı sınıflarda olduğu gibi interface yani arayüzlerin de ait oldukları isim alanları yani namespaceler var. Dosyanın başına içinde bulunduğumuz namespace’yi belirttik. Aslında doğrudan Entry sınıfını yazabilirdim ama metodların içerisini doldurmaya üşendiğim için interface yazmayı tarcih ettim. Sınıfları parçalarken gaza gelip atomu parçalamaya kadar gidebiliriz ama başımıza büyük bela alırız.

O kadar çok berbat kod gördüm ki, artık dünyaya ben de böyle bakıyorum.

Einstein’in şöyle bir lafı var:

Everything should be made as simple as possible, but not simpler. Albert Einstein

Yani meali, “Herşey olabildiğince basit yapılmalıdır, ancak bundan daha basit olmamalıdır.” O yüzden şimdilik başta karar verdiğimiz görev ve sorumlulukların dışında nesneler oluşturmuyoruz ki proje bitsin.

Arayüzü satır satır okumaya devam edelim.

  1. setKey: metin olarak bir başlık alacak. Girdinin başlığını belirliycek.
  2. getKey: başlığı metin olarak döndürecek.
  3. setValues: girdi içindeki açıklama listesini doğrudan değiştirmemizi sağlayacak. Şimdi farkettiğim üzere şimdilik bu metoda ihtiyacımız yok. Basitlik, bilgi gizleme ve güvenlik açısından silebiliriz. Ne kadar az metod o kadar kolay kullanım çünkü.
  4. getValues: girdiye ait başlıkları doğrudan dizi olarak döndüren metod.
  5. getValue: değerine erişmek istediğimiz açıklamaya sırasını belirterek erişmemizi sağlayan metod.
  6. setValue: değerine değiştirmek istediğimiz açıklamaya sırasını belirterek değiştirmemizi sağlayan metod.
  7. addValue: Sıra belirtmeden, doğrudan açıklamalar dizisine açıklama eklememizi sağlayan metod. Kolay kullanım için.
  8. deleteValue: Sıra belirterek istediğimiz açıklama değerini silmemizi sağlayan metod.

Gördüğümüz gibi, elimizde bağımsız, başka bir sınıfla alakası olmayan, kendi başına bir program gibi kullanabileceğimiz bir sınıf arayüzü oluştu.

Sözlük arayüzü yani DictionaryInterface

Şimdi Sözlük sınıfına baştan yeni bir arayüz yazalım ve bu arayüz de girdileri yönetmek için bu girdi arayüzünü kullansın.

<?php

namespace
MidoriKocak;

interface DictionaryInterface
{
function setTitle(string $title);
function getTitle(): string;
function setEntries(array $array);
function getEntries(): array;
function addEntry(EntryInterface $entry);
function getEntry(string $key): EntryInterface;
function deleteEntry(string $key);
}

Bu arayüzü de satır satır inceleyelim.

  1. setTitle: Oluşturacağımız sözlüğün başlık değişkenini değiştirmemizi, metin tipinde bir parametre alarak sağlayan metod. (set metodlarının hiçbirşey döndürmediğine dikkat edin. Set metodlarında hata olup olmadığını nasıl anlayacağız peki? Buna da hata denetimi konusuna geldiğimizde detaylıca değineceğim.)
  2. getTitle: Başlık değişkenini metin olarak döndürmek zorunda olan metod.
  3. addEntry: Sözlüğümüze entry yani girdi sınıfından bir nesneyi eklememizi sağlar. Set yerine add yani ekle ifadesini kullandık ki, sınıfta birden fazla entry yani girdi tutulduğu metodun adından anlaşılsın.
  4. getEntry: (metin tipinde $key) degeri girerek basliga erismemizi saglar.
  5. setEntries: Bu da sözlük sınıfında verileri tuttuğumuz diziyi değiştirmemizi sağlayan metod. Kullanırken dikkatli olmalı ve diziyi direk entries yani girdiler değişkenine eklememeli, tek tek girdiler kurallara uyuyor mu kontrol ederek sağlam verileri diziye eklemeliyiz.
  6. getEntries: Varolan verileri dizi şeklinde döndüren metod. Girdi sınıfından nesneler içeren bir dizi döndürecek.
  7. deleteEntry: Sözlükten adını belirttiğimiz girdiyi silen metod. Eğer bir girdinin hiç açıklaması yoksa, bu başlık da otomatik olarak silinmeli. Ancak buna daha sonra dikkat edeceğiz.
Minik minik nesneler

Şimdilik bu kadar. Bir sonraki yazıda bu arayüzlerin içini nasıl dolduracağımıza ve kodu nasıl kullanıp test edeceğimize bakacağız.

Sevgiyle kalın.

Bir sonraki yazıya buradan ulaşabilirsiniz:


Projelerle PHP 7

Ben Mutlu Koçak, Bilgisayar Mühendisiyim, ZCPE Sertifikasına sahibim ve “Hiç Bilmeyenler İçin İnternet Programlamaya Giriş — PHP 7” adlı kitabın yazarıyım. Kitabım: https://www.seckin.com.tr/kitap/911934237
Özgeçmişim:
http://represent.io/mtkocak.pdf 
Websitem:
http://mynameismidori.com