Sınıfların çoğunu veri alanına ayırmak yalnızca sınıf ve yöntem yalnızca sınıfları (mümkünse) iyi mi yoksa anti-kalıp mıdır?


10

Örneğin, bir sınıf genellikle sınıf üyelerine ve yöntemlerine sahiptir, örneğin:

public class Cat{
    private String name;
    private int weight;
    private Image image;

    public void printInfo(){
        System.out.println("Name:"+this.name+",weight:"+this.weight);
    }

    public void draw(){
        //some draw code which uses this.image
    }
}

Ancak Tek sorumluluk ilkesi ve Açık kapalı ilkesi hakkında okuduktan sonra, bir sınıfı DTO'ya ve yardımcı sınıfı yalnızca statik yöntemlerle ayırmayı tercih ederim, örneğin:

public class CatData{
    public String name;
    public int weight;
    public Image image;
}

public class CatMethods{
    public static void printInfo(Cat cat){
        System.out.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public static void draw(Cat cat){
        //some draw code which uses cat.image
    }
}

Tek sorumluluk ilkesine uyduğunu düşünüyorum çünkü artık CatData'nın sorumluluğu sadece verileri tutmak, yöntemleri umursamıyor (ayrıca CatMethods için). Ve ayrıca açık kapalı prensibine de uyar, çünkü yeni yöntemler eklemek için CatData sınıfını değiştirmek gerekmez.

Sorum şu: İyi mi yoksa anti-desen mi?


15
Her yerde körü körüne bir şey yapmak çünkü yeni bir konsept öğrendiğiniz her zaman bir anti-modeldir.
Kayaman

4
Verileri değiştiren yöntemlerden ayrı tutmak her zaman daha iyi olsaydı sınıfların anlamı ne olurdu? Bu, nesneye yönelik olmayan programlama gibi geliyor (kesinlikle yeri var). Bu "nesne yönelimli" olarak etiketlendiğinden, OOP tarafından sağlanan araçları kullanmak istediğinizi varsayalım?
user1118321

4
SRP'nin yasaklanması gerektiği kadar yanlış anlaşıldığını kanıtlayan bir başka soru. Verileri bir dizi kamusal alanda tutmak bir sorumluluk değildir .
user949300

1
@ user949300, sınıf bu alanlardan sorumluysa, bunları uygulamada başka bir yere taşımak elbette sıfır etkiye sahip olacaktır. Ya da başka bir deyişle, yanılıyorsunuz:% 100'ü bir sorumluluktur.
David Arno

2
@DavidArno ve R Schmitz: Alanları içeren, SRP amaçları için bir sorumluluk olarak sayılmaz. Eğer öyleyse, her şey bir DTO olacağı için OOP olamaz ve daha sonra ayrı sınıflar veriler üzerinde çalışmak için prosedürler içerecektir. Tek bir sorumluluk tek bir paydaşla ilgilidir . (Bu,
anaparadaki

Yanıtlar:


10

İki uç ("her şey özel ve hepsi (belki ilgisiz) yöntemler bir nesnede") "herkese açık ve nesnenin içinde hiçbir yöntem yok" şeklinde gösterdiniz. IMHO iyi OO modelleme hiçbiri değil , tatlı nokta ortada bir yerde.

Bir sınıfa hangi yöntemlerin veya mantığın ait olduğunu ve dışarıda neyin ait olduğunu gösteren bir turnusol testi, yöntemlerin getireceği bağımlılıklara bakmaktır. Ek bağımlılıklar getirmeyen yöntemler , verilen nesnenin soyutlamasına iyi uydukları sürece iyidir . Ek, harici bağımlılıklar gerektiren yöntemler (bir çizim kütüphanesi veya bir G / Ç kütüphanesi gibi) nadiren iyi bir seçimdir. Bağımlılık enjeksiyonu kullanarak bağımlılıkları ortadan kaldırsanız bile, etki alanı sınıfına bu tür yöntemler yerleştirmek gerçekten gerekliyse yine de iki kez düşünürdüm.

Dolayısıyla, her üyeyi herkese açık hale getirmemelisiniz veya sınıf içindeki bir nesne üzerindeki her işlem için yöntemler uygulamanız gerekmez. Alternatif bir öneri:

public class Cat{
    private String name;
    private int weight;
    private Image image;

    public String getInfo(){
        return "Name:"+this.name+",weight:"+this.weight;
    }
    public Image getImage(){
        return image;
    }
}

Şimdi Catnesne kodu kolayca uygulamak çevreleyen izin verecek kadar mantık sağlar printInfove drawhalkın tüm özelliklerini maruz kalmadan. Bu iki yöntem için doğru yer büyük ihtimalle bir tanrı sınıf değil CatMethods(çünkü printInfove drawben aynı sınıfa ait çok olası olduğunu düşünüyorum bu yüzden, büyük ihtimalle farklı endişeler vardır).

CatDrawingControllerHangisinin uyguladığını hayal edebilirim draw(ve bir Canvas nesnesini almak için bağımlılık enjeksiyonunu kullanır). Ayrıca bazı konsol çıktı ve kullanımları uygulayan başka bir sınıf hayal edebiliyorum getInfo(böylece printInfobu bağlamda eski olabilir). Ancak bu konuda mantıklı kararlar vermek için, bağlamı ve Catsınıfın gerçekte nasıl kullanılacağını bilmek gerekir .

Aslında, Fowler'in Anemik Alan Modeli eleştirmenlerini nasıl yorumladığım budur - genellikle yeniden kullanılabilir mantık için (dış bağımlılıklar olmadan) alan sınıflarının kendileri iyi bir yerdir, bu yüzden bunun için kullanılmaları gerekir. Ancak bu, orada herhangi bir mantık uygulamak anlamına gelmez, tam tersi.

Yukarıdaki örneğe (im) değişebilirlik hakkında karar vermek için hala yer bıraktığına dikkat edin. Eğer Catsınıf herhangi ayarlayıcılar maruz vermeyeceğini ve Imagekendisi değişmez bu tasarım olanak sağlayacak Catdeğişmez (ki DTO yaklaşım olmaz). Ancak, değişmezliğin davanız için gerekli olmadığını veya yardımcı olmadığını düşünüyorsanız, bu yöne de gidebilirsiniz.


Mutlu inişçileri tetikle, bu sıkıcı oluyor. Bazı eleştirmenleriniz varsa lütfen bize bildirin. Eğer varsa, yanlış anlamaları açıklığa kavuşturmaktan mutluluk duyacağım.
Doc Brown

Genel olarak cevabınıza katılıyorum ... getInfo()Bu soruyu soran biri için yanıltıcı olabilir. Sunum sorumluluklarını olduğu printInfo()gibi, DrawingControllersınıfın amacını yenerek ustaca karıştırır
Adriano Repetti

@AdrianoRepetti Bunun amacını yendiğini görmüyorum DrawingController. Bunu kabul ediyorum getInfo()ve printInfo()korkunç isimler. Düşünün toString()veprintTo(Stream stream)
candied_orange

@candid (sadece) isim hakkında değil, ne yaptığı hakkında. Bu kod sadece bir sunum ayrıntısıyla ilgilidir ve işlenen içeriği ve mantığını değil, çıktıyı etkili bir şekilde soyutladık.
Adriano Repetti

@AdrianoRepetti: dürüst olmak gerekirse, bu orijinal soruya uymak ve benim fikrimi göstermek için sadece tartışmalı bir örnek. Gerçek bir sistemde, elbette daha iyi yöntemler ve isimler hakkında karar vermeyi sağlayacak çevreleyen bir bağlam olacaktır.
Doc Brown

6

Geç cevap ama dayanamıyorum.

X'in çoğu Y sınıfı için iyi mi yoksa bir anti-desen mi?

Çoğu durumda, düşünmeden uygulanan çoğu kural çoğunlukla korkunç bir şekilde yanlış gidecektir (bu kural dahil).

Size bir nesnenin doğuşu hakkında, tasarımla değil çaresizlikle gerçekleşen, doğru, hızlı ve kirli, prosedürel bir kodun kaosunun ortasında bir hikaye anlatayım.

Stajyerim ve ben hızlı bir şekilde bir web sayfasını kazımak için bazı atmak kodu oluşturmak için çift programlama vardır. Bu kodun uzun süre yaşayacağını düşünmek için kesinlikle bir nedenimiz yok, bu yüzden işe yarayan bir şey patlatıyoruz. Tüm sayfayı bir dize olarak alıyoruz ve ihtiyacımız olan şeyleri hayal edebileceğiniz en şaşırtıcı şekilde kırıyoruz. Yargılama. İşe yarıyor.

Şimdi bunu yaparken doğrama yapmak için bazı statik yöntemler yarattım. Stajyerim sizin gibi bir DTO sınıfı yarattı CatData.

DTO'ya ilk baktığımda beni rahatsız etti. Java'nın beynime verdiği yıllar, beni kamuya açık alanlarda geri tepti. Ama C # 'da çalışıyorduk. C #, verileri değişmez hale getirme veya daha sonra kapsülleme yapma hakkınızı korumak için erken alıcılara ve ayarlayıcılara ihtiyaç duymaz. Arayüzü değiştirmeden istediğiniz zaman ekleyebilirsiniz. Belki sadece bir kesme noktası ayarlayabilirsiniz. Hepsi müşterilerinize bu konuda bir şey söylemeden. Evet C #. Boo Java.

Dilini tuttum. Kullanmadan önce bu şeyi başlatmak için statik yöntemlerimi kullandığını izledim. Yaklaşık 14 tanemiz vardı. Çirkin, ama umursamamamız için bir neden yoktu.

Sonra başka yerlerde ihtiyacımız vardı. Kendimizi kodu kopyalayıp yapıştırmak istediğimizi gördük. 14 başlangıç ​​hattı fırlatıldı. Acı çekmeye başlamıştı. Tereddüt etti ve benden fikir istedi.

İsteksizce, "bir nesneyi düşünür müsünüz?" Diye sordum.

DTO'suna tekrar baktı ve yüzünü şaşkına çevirdi. "Bu bir nesne".

"Gerçek bir nesne demek istiyorum"

"Ha?"

"Size bir şey göstereyim. Yararlı olup olmadığına siz karar verin"

Yeni bir isim seçtim ve hızlı bir şekilde şuna benzer bir şey çırptım:

public class Cat{
    CatData(string catPage) {
        this.catPage = catPage
    }
    private readonly string catPage;

    public string name() { return chop("name prefix", "name suffix"); }
    public string weight() { return chop("weight prefix", "weight suffix"); }
    public string image() { return chop("image prefix", "image suffix"); }

    private string chop(string prefix, string suffix) {
        int start = catPage.indexOf(prefix) + prefix.Length;
        int end = catPage.indexOf(suffix);
        int length = end - start;
        return catPage.Substring(start, length);
    }
}

Bu, statik yöntemlerin henüz yapmadığı hiçbir şey yapmadı. Ama şimdi 14 statik yöntemi üzerinde çalıştıkları verilerle yalnız kalabilecekleri bir sınıfa emdim.

Stajyeri kullanmaya zorlamadım. Sadece teklif ettim ve statik yöntemlere bağlı kalmak isteyip istemediğine karar verdim. Muhtemelen zaten çalıştığı şeye bağlı kalacağını düşünerek eve gittim. Ertesi gün onu bir sürü yerde kullandığını gördüm. Hala çirkin ve prosedürel olan kodun geri kalanını çözdü, ancak bu karmaşıklık artık bir nesnenin arkasında bizden gizlendi. Biraz daha iyiydi.

Şimdi buna her eriştiğinizde oldukça fazla iş yapıyor. DTO güzel bir hızlı önbellek değeridir. Bu konuda endişelendim ama biz hiç kullanarak kod herhangi bir dokunmadan ihtiyaç duyduysa önbellek ekleyebilirsiniz fark etti. Bu yüzden umursana kadar rahatsız etmeyeceğim.

DTO'lar üzerinde daima OO nesnelerine bağlı kalman gerektiğini mi söylüyorum? Hayır. DTO'nun sizi hareketli yöntemlerden koruyan bir sınırı geçmeniz gerektiğinde parlıyor. DTO'ların yeri var.

Ama OO nesneleri de öyle. Her iki aracı da nasıl kullanacağınızı öğrenin. Her birinin maliyetini öğrenin. Sorunun, durumun ve stajyerin karar vermesine izin vermeyi öğrenin. Dogma burada senin arkadaşın değil.


Cevabım zaten gülünç derecede uzun olduğundan, kodunuzu gözden geçirerek sizi bazı yanlış anlamaları devre dışı bırakmama izin verin.

Örneğin, bir sınıf genellikle sınıf üyelerine ve yöntemlerine sahiptir, örneğin:

public class Cat{
    private String name;
    private int weight;
    private Image image;

    public void printInfo(){
        System.out.println("Name:"+this.name+",weight:"+this.weight);
    }

    public void draw(){
        //some draw code which uses this.image
    }
}

Yapımcınız nerede? Bu bana işe yarayıp yaramadığını bilmek için yeterli değil.

Ancak Tek sorumluluk ilkesi ve Açık kapalı ilkesi hakkında okuduktan sonra, bir sınıfı DTO'ya ve yardımcı sınıfı yalnızca statik yöntemlerle ayırmayı tercih ederim, örneğin:

public class CatData{
    public String name;
    public int weight;
    public Image image;
}

public class CatMethods{
    public static void printInfo(Cat cat){
        System.out.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public static void draw(Cat cat){
        //some draw code which uses cat.image
    }
}

Tek sorumluluk ilkesine uyduğunu düşünüyorum çünkü artık CatData'nın sorumluluğu sadece verileri tutmak, yöntemleri umursamıyor (ayrıca CatMethods için).

Tek Sorumluluk İlkesi adına birçok aptalca şey yapabilirsiniz. Cat Strings ve Cat ints'ın ayrılması gerektiğini söyleyebilirim. Bu çizim yöntemlerinin ve Görseller'in kendi sınıfları olmalıdır. Çalışan programınızın tek bir sorumluluk olduğunu, bu yüzden sadece bir sınıfınız olmalıdır. : P

Bana göre, Tek Sorumluluk İlkesini izlemenin en iyi yolu, bir kutuya karmaşıklığı koymanıza izin veren iyi bir soyutlama bulmaktır. Eğer insanlara, içine baktıklarında buldukları şeylerden şaşmamak için iyi bir isim verebilirseniz, onu oldukça iyi takip ettiniz. Bunun daha fazla karar vermesini beklemek, o zaman sorun istiyor. Dürüst olmak gerekirse, kod listelemelerinizin her ikisi de bunu yapıyor, bu yüzden SRP'nin neden önemli olduğunu anlamıyorum.

Ve ayrıca açık kapalı prensibine de uyar, çünkü yeni yöntemler eklemek için CatData sınıfını değiştirmek gerekmez.

Peki hayır. Açık kapanış ilkesi yeni yöntemler eklemekle ilgili değildir. Eski yöntemlerin uygulanmasını değiştirmek ve hiçbir şeyi düzenlemek zorunda kalmakla ilgilidir. Eski yöntemlerinizi değil, sizi kullanan hiçbir şey yok. Bunun yerine başka bir yere yeni bir kod yazarsınız. Bir çeşit polimorfizm bunu güzel yapacak. Burada görmüyorum.

Sorum şu: İyi mi yoksa anti-desen mi?

Pekala, nasıl bilebilirim? Bak, her iki şekilde yapmanın faydaları ve maliyetleri var. Kodu verilerden ayırdığınızda, diğerini yeniden derlemek zorunda kalmadan değiştirebilirsiniz. Belki bu sizin için kritik öneme sahiptir. Belki de kodunuzu anlamsız bir şekilde karmaşık hale getirir.

Sizi daha iyi hissettirirse, Martin Fowler bir parametre nesnesi olarak adlandırılan bir şeyden çok uzak değilsiniz . Nesnenize sadece ilkelleri almak zorunda değilsiniz.

Yapmanızı istediğim şey, her iki kodlama stilinde de ayrılmanızın nasıl yapılacağına dair bir his geliştirmektir. Çünkü ister inanın ister inanmayın, bir stil seçmek zorunda değilsiniz. Sadece seçiminizle yaşamak zorundasınız.


2

On yıldan uzun bir süredir geliştiriciler arasında tartışma yaratan bir tartışma konusuna rastladınız. 2003 yılında Martin Fowler , bu veri ve işlevsellik ayrımını tanımlamak için "Anemik Alan Modeli" (ADM) ifadesini kullanmıştır . O ve onunla aynı fikirde olan diğerleri, "Zengin Etki Alanı Modelleri" nin (veri ve işlevselliği karıştırma) "uygun OO" olduğunu ve ADM yaklaşımının OO olmayan bir anti-desen olduğunu savunuyor.

Her zaman bu argümanı reddedenler olmuştur ve argümanın bu tarafı, son yıllarda daha fazla işlevsel geliştirme tekniği geliştiricisinin benimsemesi ile daha yüksek ve daha cesurlaşmıştır. Bu yaklaşım aktif olarak veri ve işlev kaygılarını ayırmayı teşvik eder. Veriler mümkün olduğunca değişmez olmalıdır, bu nedenle değişebilir durumun kapsüllenmesi endişe yaratmaz. Bu gibi durumlarda işlevlerin doğrudan bu verilere eklenmesinin bir yararı yoktur. O zaman "OO değil" olsun ya da olmasın böyle bir halk için kesinlikle hiçbir ilgi yoktur.

Çitin hangi tarafına oturduğunuzdan bağımsız olarak ("Martin Fowler, eski tosh yükünden konuşuyor" tarafı BTW), statik yöntemler kullanmanız printInfove drawneredeyse evrensel olarak kaşlarını çatmak için çok sıkı oturuyorum . Birim testleri yazarken statik yöntemlerin taklit edilmesi zordur. Dolayısıyla, yan etkileri varsa (bazı ekranlara veya başka bir cihaza yazdırma veya çizim gibi), statik olmamalıdır veya çıktı konumunun parametre olarak iletilmesi gerekir.

Böylece bir arayüzünüz olabilir:

public interface CatMethods {
    void printInfo(Cat cat);
    void draw(Cat cat);
}

Ve çalışma zamanında sisteminizin geri kalanına enjekte edilen bir uygulama (test için diğer uygulamalar kullanılıyor):

internal class CatMethodsForScreen implements CatMethods {
    public void printInfo(Cat cat) {
        System.out.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public void draw(Cat cat) {
        //some draw code which uses cat.image
    }
}

Veya bu yöntemlerden yan etkileri kaldırmak için ekstra parametreler ekleyin:

public static class CatMethods {
    public static void printInfo(Cat cat, OutputHandler output) {
        output.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public static void draw(Cat cat, Canvas canvas) {
        //some draw code which uses cat.image and draws it on canvas
    }
}

Ama neden Java gibi bir OO dilini başlangıçtan itibaren işlevsel bir dile gitmek yerine işlevsel bir dile sokmaya çalışıyorsunuz? Bir çeşit "Java'dan nefret ediyorum, ama herkes bunu kullanıyor, bu yüzden yapmam gerekiyor, ama en azından kendi yolumla yazacağım". OO paradigmasının bir şekilde modası geçmiş ve modası geçmiş olduğunu iddia etmiyorsanız. "X istiyorsanız, nereden alacağınızı biliyorsunuz" düşünce okuluna abone oluyorum.
Kayaman

@Kayaman, " Ben" X istiyorsanız, nereden alacağınızı biliyorsunuz "düşünce okulu ". Yapmıyorum. Bu tutumu hem kısa görüşlü hem de biraz rahatsız edici buluyorum. Java kullanmıyorum, ancak C # kullanıyorum ve bazı "gerçek OO" özelliklerini yok sayıyorum. Kalıtım, durum bilgisi olan nesneler ve benzerlerini umursamıyorum ve çok sayıda statik yöntem ve kapalı (son) sınıflar yazıyorum. C # çevresindeki araç ve topluluk boyutu hiçbiri ikinci değil. F # için, bu çok daha zayıf. Bu yüzden "X istiyorsanız, mevcut takımınıza eklenmesini isteyin" düşünce okuluna abone olurum.
David Arno

1
Bir dilin yönlerini görmezden gelmenin, diğer dillerdeki özellikleri karıştırmaya ve eşleştirmeye çalışmaktan çok farklı olduğunu söyleyebilirim. "Gerçek OO" yazmaya da çalışmıyorum, çünkü programlama gibi yanlış bir bilimde kuralları (veya ilkeleri) takip etmeye çalışmak işe yaramıyor. Tabii ki kuralları bilmeniz gerekir ki onları kırabilirsiniz. Özelliklere körü körüne başvurmak dilin gelişimi için kötü olabilir. Suç yok, ama IMHO FP sahnesinin bir parçası "FP, dilimlenmiş ekmeklerden bu yana en büyük şey, neden insanlar bunu anlamıyor?" OO ya da Java asla "en iyisi" demem (ya da düşünmem).
Kayaman

1
@Kayaman, ama "diğer dillerdeki özellikleri karıştırmaya ve eşleştirmeye çalışmak" ne anlama geliyor? "Java bir OO dilidir" diye java'ya işlevsel özelliklerin eklenmemesi gerektiğini mi düşünüyorsunuz? Eğer öyleyse, bence bu kısa görüşlü bir argüman. Dil, geliştiricilerin istekleri ile gelişsin. Onları başka bir dile geçmeye zorlamak yanlış bir yaklaşımdır. Tabii ki bazı "FP savunucuları" FP şimdiye kadar en iyi şey olmak üst üzerinde gidin. Ve bazı "OO savunucuları" OO'nun "savaşı kazandığı için açıkça üstün olduğu için" en üst seviyeye çıkıyor. İkisini de görmezden gelin.
David Arno

1
FP karşıtı değilim. Yararlı olduğu Java'da kullanıyorum. Ama bir programcı "Bunu istiyorum" derse, "Bunu istiyorum" diyen bir müşteri gibi. Programcılar dil tasarımcıları değil, istemciler de programcı değildir. OP'nin "çözümünün" kaşlarını çattığını söylediğiniz için cevabınızı iptal ettim. Yine de sorudaki yorum daha kısa, yani bir OO dilinde prosedürel programlamayı yeniden keşfetti. Gösterdiğiniz gibi genel fikrin bir anlamı var. Anemik olmayan bir alan modeli, verilerin ve davranışların münhasır olduğu ve dış oluşturucuların veya sunum yapan kişilerin yasak olacağı anlamına gelmez.
Kayaman

0

DTOs - Veri Taşıma Nesneleri

bunun için yararlıdır. Programlar veya sistemler arasında veriyi şönt edecekseniz, sadece veri yapısı ve biçimlendirmesi ile ilgilenen bir nesnenin yönetilebilir bir alt kümesini sağladıkları için DTO'lar tercih edilir. Bunun avantajı, güncellemeleri çeşitli sistemlerde karmaşık yöntemlerle senkronize etmek zorunda olmamanızdır (temel veriler değişmediği sürece).

OO'nun tüm amacı, verileri ve bu verilere etki eden kodu birbirine yakından bağlamaktır. Mantıksal bir Nesneyi ayrı sınıflara ayırmak genellikle kötü bir fikirdir.


-1

Birçok tasarım deseni ve ilkesi çelişir ve sonuçta sadece iyi bir programcı olarak sizin kararınız, belirli bir sorun için hangi kalıpların uygulanacağına karar vermenize yardımcı olacaktır.

Bence, tasarımı daha karmaşık hale getirmek için güçlü bir nedeniniz yoksa, Muhtemelen Çalışabilecek En Basit Şey Yap prensibi varsayılan olarak kazanmalıdır. Dolayısıyla, özel örneğinizde, aynı sınıfta veri ve işlevlerle birlikte daha geleneksel bir nesne yönelimli yaklaşım olan ilk tasarımı tercih ederim.

Uygulama hakkında kendinize sorabileceğiniz birkaç soru:

  • Bir Cat resmini oluşturmanın alternatif bir yolunu sunmam gerekecek mi? Eğer öyleyse, kalıtım bunu yapmanın uygun bir yolu olmayacak mı?
  • Cat sınıfımın başka bir sınıftan miras alması veya bir arabirimi karşılaması gerekiyor mu?

Bunlardan herhangi birine evet yanıtı vermek, ayrı DTO ve fonksiyonel sınıflarla daha karmaşık bir tasarıma yol açabilir.


-1

İyi bir model mi?

Muhtemelen burada farklı cevaplar alacaksınız çünkü insanlar farklı düşünce okullarını takip ediyor. Bu yüzden başlamadan önce: Bu cevap Robert C. Martin tarafından "Temiz Kod" kitabında anlatıldığı gibi nesneye yönelik programlamaya göre.


"Doğru" OOP

Bildiğim kadarıyla, OOP'un 2 yorumu var. Çoğu insan için "nesne bir sınıftır" diye kaynar.

Ancak, diğer düşünce okulunu daha yararlı buldum: "Bir nesne bir şey yapan bir şeydir". Sınıflarla çalışıyorsanız, her sınıf iki şeyden biri olacaktır: bir " veri sahibi " veya bir nesne . Veri sahipleri verileri tutar (duh), nesneler bir şeyler yapar. Bu, veri sahibinin yöntemlere sahip olamayacağı anlamına gelmez! Bir düşünün list: A listgerçekten hiçbir şey yapmaz , ancak verileri tutma biçimini zorlamak için yöntemleri vardır .

Veri sahipleri

Sen Catbir veri sahibinin bir örnektir. Elbette, programınızın dışında bir şey bir şey yapan bir şeydir , ancak programınızın içinde a Catbir String name, int weightve Image'dir image.

Bu veriler sahipleri yok yapmak onlar iş mantığı içermeyen anlamına gelmez, aynı zamanda bir şey! Senin Eğer Catsınıf gerektiren bir kurucuya sahip name, weightve imagebaşarıyla Her kedinin olanlar olduğu iş kuralı kapsüllü ettik. weightBir Catsınıf oluşturulduktan sonra değiştirebiliyorsanız , bu kapsüllenmiş başka bir iş kuralıdır. Bunlar çok temel şeyler, ama bu sadece onları yanlış anlamamanın çok önemli olduğu anlamına geliyor - ve bu şekilde, bunu yanlış yapmanın imkansız olmasını sağlıyorsunuz.

Nesneler

Nesneler bir şey yapar. Temiz * nesneler istiyorsanız , bunu "Nesneler bir şey yapar" olarak değiştirebiliriz.

Kedi bilgisini basmak bir nesnenin işidir. Örneğin, bu nesneyi CatInfoLoggergenel bir yöntemle " " olarak adlandırabilirsiniz Log(Cat). Dışarıdan bilmemiz gereken tek şey bu: Bu nesne bir kedinin bilgisini günlüğe kaydeder ve bunu yapmak için a'ya ihtiyacı vardır Cat.

İçeride, bu nesnenin kedileri günlüğe kaydetmenin tek sorumluluğunu yerine getirmek için ihtiyaç duyduğu her şeye referanslar olacaktır . Bu durumda, bu sadece bir referans var Systemiçin System.out.println, ancak çoğu durumda, diğer nesnelere özel referanslar olacaktır. Çıktıyı yazdırmadan önce biçimlendirme mantığı çok karmaşık hale gelirse, CatInfoLoggeryeni bir nesneye referans alabilirsiniz CatInfoFormatter. Daha sonra, her günlüğün bir dosyaya da yazılması gerekiyorsa, bunu CatToFileLoggeryapan bir nesne ekleyebilirsiniz .

Veri Tutucular ve Nesneler - Özet

Şimdi, neden tüm bunları yapasın ki? Çünkü şimdi bir sınıfı değiştirmek sadece bir şeyi değiştirir ( bir kedinin örnekte oturum açma şekli ). Bir nesneyi değiştiriyorsanız, yalnızca belirli bir eylemin gerçekleştirilme şeklini değiştirirsiniz; bir veri sahibini değiştirirseniz, yalnızca hangi verilerin tutulduğunu ve / veya hangi şekilde tutulduğunu değiştirirsiniz.

Verilerin değiştirilmesi, bir şeyin yapılma şeklinin de değişmesi gerektiği anlamına gelebilir, ancak bu değişiklik, sorumlu nesneyi değiştirerek kendiniz gerçekleşene kadar gerçekleşmez.

Aşırı yükleme?

Bu çözüm biraz abartılı gelebilir. Açık söz edeyim: Öyle . Tüm programınız sadece örnek kadar büyükse, yukarıdakilerden herhangi birini yapmayın - sadece bir bozuk para atma ile önerilen yollardan birini seçin. Başka bir kod yoksa , başka kodların karıştırılması tehlikesi yoktur.

Bununla birlikte, herhangi bir "ciddi" (= bir komut dosyasından veya 2'den fazla) yazılım muhtemelen böyle bir yapıdan kazanç sağlayacak kadar büyüktür.


Cevap

Çoğu sınıfı DTO ve yardımcı sınıflara ayırmak [...] iyi mi yoksa anti-kalıp mıdır?

"Çoğu sınıfın" (başka bir nitelik olmadan) DTO'lara / veri sahiplerine dönüştürülmesi bir anti-desen değildir, çünkü aslında herhangi bir desen değildir - az ya da çok rastgeledir.

Ancak verileri ve nesneleri ayrı tutmak kodunuzu temiz tutmanın iyi bir yolu olarak görülür *. Bazen sadece düz, "anemik" bir DTO'ya ihtiyacınız olacaktır ve hepsi bu kadar. Diğer zamanlarda, verilerin tutulma şeklini zorlamak için yöntemlere ihtiyacınız vardır. Programınızın işlevselliğini verilerle birlikte koymayın.


* Bu kitap başlığı gibi bir C harfi ile "Temiz", çünkü - ilk paragrafı unutmayın - bu bir düşünce okulu hakkında, diğerleri de var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.