Çok sayıda insan çoktan cevapladı. Kendi kişisel bakış açımı verebileceğimi düşündüm.
Bir zamanlar müzik yapan bir uygulama üzerinde çalıştım.
Uygulamanın soyut vardı Scale
: Birkaç alt sınıf ile sınıf CMajor
, DMinor
vb Scale
yüzden böyle bir şey görünüyordu:
public abstract class Scale {
protected Note[] notes;
public Scale() {
loadNotes();
}
// .. some other stuff ommited
protected abstract void loadNotes(); /* subclasses put notes in the array
in this method. */
}
Müzik jeneratörleri Scale
, müzik üretmek için belirli bir örnekle çalıştı . Kullanıcı, müzik yapmak için listeden bir ölçek seçer.
Bir gün havalı bir fikir aklıma geldi: neden kullanıcının kendi ölçeklerini yaratmasına izin vermiyor? Kullanıcı listeden notları seçer, bir düğmeye basar ve listedeki mevcut ölçeklere yeni bir ölçek eklenir.
Ama bunu yapamadım. Bunun nedeni, tüm ölçeklerin zaten derleme zamanında ayarlanmış olmasıdır - çünkü sınıf olarak ifade edilirler. Sonra bana vurdu:
“Süper sınıflar ve alt sınıflar” anlamında düşünmek çoğu zaman sezgiseldir. Hemen hemen her şey bu sistem aracılığıyla ifade edilebilir: üst sınıf Person
ve alt sınıflar John
ve Mary
; üst sınıf Car
ve alt sınıflar Volvo
ve Mazda
; SuperClass Missile
ve alt sınıfları SpeedRocked
, LandMine
ve TrippleExplodingThingy
.
Bu şekilde düşünmek çok doğal, özellikle de OO için nispeten yeni olan biri için.
Ancak sınıfların şablon olduğunu ve nesnelerin bu şablonlara içerik döktüğünü daima hatırlamalıyız . Sayısız olasılık oluşturarak, şablona istediğiniz içeriği dökün.
Şablonu doldurmak alt sınıfın işi değildir. Bu nesnenin işi. Alt sınıfın işi, gerçek işlevsellik eklemek veya şablonu genişletmektir .
İşte bu yüzden Scale
, bir Note[]
alan içeren somut bir sınıf yaratmalı ve nesnelerin bu şablonu doldurmasına izin vermeliydim ; muhtemelen yapıcı veya başka bir şey aracılığıyla. Ve nihayet yaptım.
Bir sınıfta bir şablon tasarladığınızda (örneğin Note[]
doldurulması gereken boş bir üye veya String name
değer atanması gereken bir alan), şablonu doldurmak için bu sınıftaki nesnelerin işi olduğunu unutmayın ( veya muhtemelen bu nesneleri yaratanlar). Alt sınıflar, şablonları doldurmamak için işlevsellik eklemek içindir.
"Süper sınıf Person
, alt sınıflar John
ve Mary
" gibi bir sistem yaratmaya istekli olabilirsiniz , çünkü böyle bir biçim alırsınız.
Bu şekilde, sadece söyleyebiliriz Person p = new Mary()
yerine, Person p = new Person("Mary", 57, Sex.FEMALE)
. İşleri daha organize ve daha yapılandırılmış hale getirir. Ancak dediğimiz gibi, her veri kombinasyonu için yeni bir sınıf oluşturmak iyi bir yaklaşım değildir, çünkü hiçbir şeyin kodunu engeller ve çalışma zamanı yetenekleri açısından sizi sınırlar.
Öyleyse işte çözüm: temel bir fabrika kullanın, hatta statik bir fabrika bile olabilir. Bunun gibi:
public final class PersonFactory {
private PersonFactory() { }
public static Person createJohn(){
return new Person("John", 40, Sex.MALE);
}
public static Person createMary(){
return new Person("Mary", 57, Sex.FEMALE);
}
// ...
}
Bu şekilde, 'önceden ayarlanmış' olan 'programla birlikte gelen' kolayca kullanabilirsiniz: Person mary = PersonFactory.createMary()
ancak örneğin, kullanıcının yapmasına izin vermek istemeniz durumunda dinamik olarak yeni kişiler tasarlama hakkını da saklı tutarsınız. . Örneğin:
// .. requesting the user for input ..
String name = // user input
int age = // user input
Sex sex = // user input, interpreted
Person newPerson = new Person(name, age, sex);
Ya da daha iyisi: Böyle bir şey yapın:
public final class PersonFactory {
private PersonFactory() { }
private static Map<String, Person> persons = new HashMap<>();
private static Map<String, PersonData> personBlueprints = new HashMap<>();
public static void addPerson(Person person){
persons.put(person.getName(), person);
}
public static Person getPerson(String name){
return persons.get(name);
}
public static Person createPerson(String blueprintName){
PersonData data = personBlueprints.get(blueprintName);
return new Person(data.name, data.age, data.sex);
}
// .. or, alternative to the last method
public static Person createPerson(String personName){
Person blueprint = persons.get(personName);
return new Person(blueprint.getName(), blueprint.getAge(), blueprint.getSex());
}
}
public class PersonData {
public String name;
public int age;
public Sex sex;
public PersonData(String name, int age, Sex sex){
this.name = name;
this.age = age;
this.sex = sex;
}
}
Kendini kaptırdım. Sanırım fikri anladın.
Alt sınıflar, üst sınıfları tarafından belirlenen şablonları doldurmaya yönelik değildir. Alt sınıflar işlevsellik eklemek içindir . Nesne , şablonları doldurmak içindir, onlar bunun içindir.
Her olası veri kombinasyonu için yeni bir sınıf oluşturmamalısınız. (Tıpkı Scale
olası her Note
s birleşimi için yeni bir alt sınıf oluşturmamam gerektiği gibi ).
Her bir kılavuz: Ne zaman yeni bir alt sınıf oluşturursanız, üst sınıfta olmayan yeni bir işlevsellik eklediğini düşünün. Bu sorunun cevabı "hayır" ise, üst sınıfın 'şablonunu doldurmaya' çalışıyorsanız, bu durumda sadece bir nesne oluşturun. (Ve muhtemelen hayatı daha kolay hale getirmek için 'ön ayarlı' bir Fabrika).
Umarım yardımcı olur.