Anlamsal alan adınızın IS-A ilişkisine sahip olduğu anlaşılıyor, ancak bunu modellemek için alt türler / kalıtım kullanmaktan, özellikle de çalışma zamanı türü yansıması nedeniyle biraz dikkatli olursunuz. Bununla birlikte, yanlış şeyden korktuğunuzu düşünüyorum - altyazı gerçekten tehlikelerle geliyor, ancak çalışma zamanında bir nesneyi sorguladığınız gerçeği sorun değil. Ne demek istediğimi anlayacaksın.
Nesne yönelimli programlama, IS-A ilişkileri nosyonuna oldukça eğildi, tartışmasız olarak çok ciddi bir şekilde eğildi, bu da iki ünlü eleştirel konsepte yol açtı:
Ancak, IS-A ilişkilerine bakmanın belki de bu güçlükleri olmayan başka bir işlevsel programlama tabanlı başka bir yol olduğunu düşünüyorum. İlk olarak, biz bir yaşayacaksın yüzden, bizim programda atlar ve tek boynuzlu modellemek istiyoruz Horse
ve bir Unicorn
tür. Bu türlerin değerleri nelerdir? Şunu söyleyebilirim ki:
- Bu türlerin değerleri (sırasıyla) atların ve tek boynuzlu atların temsilleri veya açıklamalarıdır ;
- Bunlar şematik gösterimler veya açıklamalardır; serbest biçimli değillerdir, çok katı kurallara göre inşa edilmişlerdir.
Kulağa açık gelebilir, ancak bence insanların daire elips sorunu gibi konulara girme yollarından biri, bu noktalara yeterince dikkat etmeyerek. Her daire bir elipstir, ancak bu, bir dairenin her şematik tanımının otomatik olarak bir elipsin farklı bir şemaya göre şematik bir açıklaması olduğu anlamına gelmez. Başka bir deyişle, bir dairedir sırf bir elips bir anlamına gelmez Circle
bir olduğunu Ellipse
, tabiri caizse. Ancak bu demek oluyor ki:
- Bir bulunmaktadır eden toplam fonksiyon bir dönüştürür
Circle
bir halinde (şematik daire açıklama) Ellipse
aynı daireleri anlatan (bilgi farklı tip);
- Bir daire tanımlayan ve karşılık gelen döndüren bir kısmi fonksiyon vardır .
Ellipse
Circle
Bu nedenle, işlevsel programlama terimlerinde, Unicorn
türünüzün bir alt tür olması gerekmez Horse
, sadece aşağıdaki gibi işlemlere ihtiyacınız vardır:
-- Convert any unicorn-description of into a horse-description that
-- describes the same unicorns.
toHorse :: Unicorn -> Horse
-- If the horse described by the given horse-description is a unicorn,
-- then return a unicorn-description of that unicorn, otherwise return
-- nothing.
toUnicorn :: Horse -> Maybe Unicorn
Ve toUnicorn
bunun tam tersi olması gerekir toHorse
:
toUnicorn (toHorse x) = Just x
Haskell'in Maybe
türü, diğer dillerin "seçenek" türü dedikleri şeydir. Örneğin, Java 8 Optional<Unicorn>
tipi ya bir Unicorn
ya hiçdir. Alternatiflerinizden ikisinin (bir istisna atma veya "varsayılan veya sihirli bir değer" döndürme) seçenek türlerine çok benzer olduğunu unutmayın.
Temel olarak burada yaptığım şey, alt tipler veya kalıtım kullanmadan, IS-A ilişkisini türler ve işlevler açısından yeniden yapılandırmaktır. Bundan uzak tutacağım şey:
- Modelinizin bir
Horse
türü olması gerekiyor ;
Horse
Türü ihtiyacı olan herhangi bir değer, bir tek boynuzlu tarif olup açıkça belirlemek için yeterli bilgi kodlamak için;
- Türün bazı işlemlerinin, bu
Horse
tür bilgileri Horse
istemesi için belirli bir unicorn olup olmadığını gözlemleyebilmesi için bu tür bilgileri açığa çıkarması gerekir ;
- Türün istemcileri,
Horse
bu sonraki işlemleri tek boynuzlu atlar ve atlar arasında ayrım yapmak için çalışma zamanında kullanmak zorunda kalacak.
Yani bu temelde bir " Horse
tek boynuzlu at olup olmadığını sormak " bir modeldir. Sen bu modele karşı temkinlisin, ama bence yanlış. Size bir Horse
s listesi verirseniz , söz konusu olanın garanti ettiği şey, listedeki öğelerin tanımladığı şeylerin atlar olduğudur - kaçınılmaz olarak, çalışma zamanında hangisinin tek boynuzlu olduğunu söylemek için bir şeyler yapmanız gerekir. Dolayısıyla, bunun üstesinden gelmek yok, bence - sizin için yapacak işlemleri yapmanız gerekiyor.
Nesne yönelimli programlamada, bunu yapmanın bilinen yolu şudur:
- Bir
Horse
tür var;
- Var
Unicorn
bir alt tipi olarak Horse
;
- Belirli
Horse
bir zaman olup olmadığını belirleyen, istemci tarafından erişilebilir bir işlem olarak çalışma zamanı türü yansımasını kullanın Unicorn
.
Bu, yukarıda sunduğum "şey ve açıklama" açısından bakarken, çok büyük bir zayıflık var:
- Tek
Horse
boynuzlu atı tarif eden, ancak bir Unicorn
örnek olmayan bir örneğiniz varsa?
En başa dönersek, bu bir IS-A ilişkisini modellemek için alt yazı ve alt pencereleri kullanmanın gerçekten korkutucu bir parçası olduğunu düşünüyorum - bir çalışma zamanı kontrolü yapmanız gerekmiyor. Tipografiyi biraz kötüye kullanmak, Horse
bunun bir Unicorn
örnek olup olmadığını sormak Horse
, tek boynuzlu at olup olmadığını sormakla eşanlamlı değildir ( Horse
aynı zamanda tek boynuzlu at olan bir atın tanımı olup olmadığı ). Programınız, bir kodu tekboynuzlu atı tarif Horses
eden bir müşteri kurmaya çalıştığında yapılandıran kodu kapatacak kadar uzun Horse
sürmediyse, Unicorn
sınıf başlatılır. Tecrübelerime göre, nadiren programcılar bunu dikkatlice yaparlar.
Bu yüzden, Horse
s'yi Unicorn
s'ye çeviren açık ve aşağı olmayan bir işlemin olduğu yaklaşıma giderdim . Bu, aşağıdaki Horse
türden bir yöntem olabilir :
interface Horse {
// ...
Optional<Unicorn> toUnicorn();
}
... ya da harici bir nesne olabilir ("atın tek boynuzlu at olup olmadığını söyleyen bir at üzerindeki ayrı nesnen"):
class HorseToUnicornCoercion {
Optional<Unicorn> convert(Horse horse) {
// ...
}
}
Bunların arasında seçim yapmak, programınızın nasıl organize edildiğine ilişkin bir konudur - her iki durumda da, işlemimin Horse -> Maybe Unicorn
yukarıdan eşdeğeri vardır, sadece farklı şekillerde paketliyorsunuzdur (kuşkusuz bu tür işlemlerin ne tür işlemler Horse
gerektirdiği üzerinde dalgalanma etkileri olacaktır. müşterilerine göstermek için).