Kamu Hizmeti Duyurusu:
Ben özellikleri için hemen hemen her zaman bir kod kokusu olduğunu ve kompozisyon lehine kaçınılması gerektiğini düşünüyorum kayıt için belirtmek istiyorum. Benim düşünceme göre, tek bir kalıtımın bir anti-desen olma noktasına kadar kötüye kullanıldığı ve çoklu kalıtımın sadece bu sorunu birleştirdiğini düşünüyorum. Çoğu durumda miras yerine kompozisyonu tercih ederek çok daha iyi hizmet edersiniz (tek veya çoklu olsun). Hala özellikler ve arayüzlerle ilişkileri ile ilgileniyorsanız, okumaya devam edin ...
Bunu söyleyerek başlayalım:
Nesneye Dayalı Programlama (OOP) kavramak zor bir paradigma olabilir. Sınıfları kullanmanız, kodunuzun Nesneye Dayalı (OO) olduğu anlamına gelmez.
OO kodu yazmak için, OOP'nin gerçekten nesnelerinizin yetenekleri hakkında olduğunu anlamanız gerekir. Sınıfları, gerçekte yaptıkları yerine yapabilecekleri açısından düşünmelisiniz . Bu, biraz kod "bir şey yap" yapmaya odaklanılan geleneksel prosedürel programlamanın tam tersidir.
OOP kodu planlama ve tasarımla ilgiliyse, bir arayüz mavikopyadır ve bir nesne tamamen inşa edilmiş evdir. Bu arada, özellikler, planın (arayüz) ortaya koyduğu evi inşa etmeye yardımcı olmanın bir yoludur.
Arayüzler
Peki, neden arayüzler kullanmalıyız? Oldukça basit, arayüzler kodumuzu daha az kırılgan hale getirir. Bu ifadeden şüpheleniyorsanız, arabirimlere karşı yazılmamış olan eski kodu korumak zorunda kalan herkesten isteyin.
Arayüz, programcı ve kodu arasında yapılan bir sözleşmedir. Arayüz, "Kurallara göre oynadığınız sürece beni istediğiniz gibi uygulayabilirsiniz ve söz veriyorum diğer kodunuzu kırmayacağım."
Bu nedenle, örnek olarak, gerçek dünya senaryosunu düşünün (araba veya widget yok):
Bir web uygulamasının sunucu yükünü azaltmak için bir önbellek sistemi uygulamak istiyorsunuz
APC kullanarak istek yanıtlarını önbelleğe almak için bir sınıf yazarak işe başlarsınız:
class ApcCacher
{
public function fetch($key) {
return apc_fetch($key);
}
public function store($key, $data) {
return apc_store($key, $data);
}
public function delete($key) {
return apc_delete($key);
}
}
Ardından, HTTP yanıt nesnenizde, gerçek yanıtı oluşturmak için tüm işleri yapmadan önce bir önbellek isabetini kontrol edersiniz:
class Controller
{
protected $req;
protected $resp;
protected $cacher;
public function __construct(Request $req, Response $resp, ApcCacher $cacher=NULL) {
$this->req = $req;
$this->resp = $resp;
$this->cacher = $cacher;
$this->buildResponse();
}
public function buildResponse() {
if (NULL !== $this->cacher && $response = $this->cacher->fetch($this->req->uri()) {
$this->resp = $response;
} else {
// Build the response manually
}
}
public function getResponse() {
return $this->resp;
}
}
Bu yaklaşım harika çalışıyor. Ancak birkaç hafta sonra APC yerine dosya tabanlı bir önbellek sistemi kullanmaya karar verdiniz. Artık denetleyicinizin kodunu değiştirmeniz gerekir, çünkü denetleyicinizi ApcCacher
sınıfın yeteneklerini ifade eden bir arabirim yerine sınıfın işlevselliğiyle çalışacak şekilde programladınız ApcCacher
. Diyelim ki yukarıdakilerin yerine Controller
sınıfı böyle bir CacherInterface
beton yerine bağımlı hale getirdiniz ApcCacher
:
// Your controller's constructor using the interface as a dependency
public function __construct(Request $req, Response $resp, CacherInterface $cacher=NULL)
Bununla devam etmek için arayüzünüzü şöyle tanımlarsınız:
interface CacherInterface
{
public function fetch($key);
public function store($key, $data);
public function delete($key);
}
Buna karşılık hem sizin hem de ApcCacher
yeni FileCacher
sınıflarınız uygular CacherInterface
ve Controller
sınıfınızı arabirimin gerektirdiği yetenekleri kullanacak şekilde programlarsınız .
Bu örnek (umarım), bir arayüze programlamanın, değişikliklerin diğer kodunuzu kıracağı konusunda endişelenmeden sınıflarınızın dahili uygulamasını nasıl değiştirebildiğinizi gösterir.
özellikleri
Diğer yandan, özellikler basitçe kodu yeniden kullanmak için bir yöntemdir. Arayüzler, özelliklere karşılıklı olarak münhasır bir alternatif olarak düşünülmemelidir. Aslında, bir arayüzün gerektirdiği yetenekleri yerine getiren özellikler oluşturmak ideal kullanım örneğidir .
Yalnızca birden fazla sınıf aynı işlevselliği paylaştığında (muhtemelen aynı arabirim tarafından dikte edilen) özellikleri kullanmalısınız. Tek bir sınıf için işlevsellik sağlamak için bir özellik kullanmanın bir anlamı yoktur: bu sadece sınıfın yaptıklarını gizler ve daha iyi bir tasarım özelliğin işlevselliğini ilgili sınıfa taşır.
Aşağıdaki özellik uygulamasını düşünün:
interface Person
{
public function greet();
public function eat($food);
}
trait EatingTrait
{
public function eat($food)
{
$this->putInMouth($food);
}
private function putInMouth($food)
{
// Digest delicious food
}
}
class NicePerson implements Person
{
use EatingTrait;
public function greet()
{
echo 'Good day, good sir!';
}
}
class MeanPerson implements Person
{
use EatingTrait;
public function greet()
{
echo 'Your mother was a hamster!';
}
}
Daha somut bir örnek: hayal hem senin FileCacher
ve seninApcCacher
arayüz tartışma kullanımından aynı yöntem bir önbellek girdisi bayat ve silinmesi gerektiğini belirlemek için (tabii ki bu gerçek hayatta durum böyle değil ama onunla gitmek). Bir özellik yazabilir ve her iki sınıfın da ortak arabirim gereksinimi için kullanmasına izin verebilirsiniz.
Son bir uyarı kelimesi: niteliklerle denize düşmemeye dikkat edin. Genellikle, benzersiz sınıf uygulamaları yeterli olduğunda, özellikler zayıf tasarım için bir koltuk değneği olarak kullanılır. En iyi kod tasarımı için özellikleri arayüz gereksinimlerini karşılamakla sınırlamalısınız.