OO dilinde mantıksal olarak prosedür yazılımı yazmanın en temiz yolu


12

Ben bir elektrik mühendisiyim ve ne yaptığımı bilmiyorum. Lütfen gelecekteki kodlarımı sakla.

Son zamanlarda işlevselliği mantıksal olarak "yordamsal" olan bir dizi küçük program (C #) üzerinde çalışıyorum. Örneğin, bunlardan biri, farklı veritabanlarından bilgi toplayan, bu bilgileri bir tür özet sayfası oluşturmak, onu yazdırmak ve sonra çıkmak için kullanan bir programdır.

Tüm bunlar için gerekli olan mantık yaklaşık 2000 satırdır. Kesinlikle hepsini tek bir şeyle doldurmak istemiyorum main()ve daha sonra #regionbazı eski geliştiriciler (shudder) yapıyor gibi s ile "temizlemek" .

Zaten memnuniyetsizce denediğim bazı şeyler:

DatabaseInfoGetter, SummaryPageGenerator ve PrintUtility gibi her kaba işlev için statik yardımcı programlar oluşturun. Ana işlevi aşağıdaki gibi yapmak:

int main()
{
    var thisThing = DatabaseInfoGetter.GetThis();
    var thatThing = DatabaseInfoGetter.GetThat();
    var summary = SummaryPageGenerator.GeneratePage(thisThing, thatThing);

    PrintUtility.Print(summary);
}

Bir program için arayüzlerle bile gittim

int main()
{
    /* pardon the psuedocode */

    List<Function> toDoList = new List<Function>();
    toDoList.Add(new DatabaseInfoGetter(serverUrl));
    toDoList.Add(new SummaryPageGenerator());
    toDoList.Add(new PrintUtility());

    foreach (Function f in toDoList)
        f.Do();
}

Bunların hiçbiri doğru gelmiyor. Kod uzadıkça, bu yaklaşımların her ikisi de çirkinleşmeye başlar.

Böyle şeyleri yapılandırmanın iyi bir yolu nedir?


2
Bunun kesinlikle bir kopya olduğundan emin değilim, ancak sırayla çağırılması gereken birçok yöntem vs birçok parametre ile Tek yöntem okuyun .


@Snowman, daha büyük kod parçaları yazmaya yeni başlayan biri olarak, bu tür sorunlarla karşılaşan tek kişi olmadığımı görmek güven vericidir. Bu soruya verdiğiniz cevabı beğendim. Yardımcı olur.
Lombard

@ Karmaşıklığı yönetilebilir bir düzeye düşürme fikri geliştirmek gerçekten iyi bir beceridir. Kimse büyük bir kod tabanını anlayamaz, hatta Süpermen'i bile (belki Batman olsa da) anlayamaz. Fikirleri basitçe ifade etmenin ve kodu kendi kendine belgelemenin yollarını bulmak çok önemlidir.

"Son zamanlarda işlevselliği mantıksal olarak" prosedürel "olan bir dizi daha küçük program üzerinde çalışıyorum. Örneğin, bunlardan biri farklı veritabanlarından bilgi toplayan, bir tür özet oluşturmak için bu bilgileri kullanan bir programdır. sayfası, yazdırır ve sonra çıkar. ":" Yordamsal "ile" zorunlu "kelimesini karıştırdığınızdan emin misiniz? Hem prosedürel hem de nesne yönelimli olmak zorunludur (yani) bir sırayla gerçekleştirilecek işlemleri ifade edebilirler.
Giorgio

Yanıtlar:


18

Profesyonel bir programcı olmadığınız için basitliğe sadık kalmanızı tavsiye ederim. Programcı için modülerleştirilmiş, prosedürel kodunuzu alıp daha sonra OO yapması çok daha kolay olacaktır, kötü yazılmış bir OO programını düzeltmelerinden daha kolay olacaktır. Eğer tecrübeli değilseniz, size ya da peşinizden gelen herkese yardımcı olmayacak, kutsal olmayan bir karmaşaya dönüşebilecek OO programları oluşturmak mümkündür.

Sanırım ilk içgüdünüz, ilk örnekte "bu şey - o şey" kodu doğru yol. Ne yapmak istediğiniz açık ve açıktır. Kod verimliliği konusunda fazla endişelenmeyin, açıklık çok daha önemlidir.

Bir kod segmenti çok uzunsa, her biri kendi işlevine sahip olan ısırık boyutundaki parçalara bölün. Çok kısaysa, daha az modül kullanmayı ve daha fazla sıraya koymayı düşünün.

---- Postscript: OO Tasarım Tuzakları

OO programlama ile başarılı bir şekilde çalışmak zor olabilir. Tüm modelin kusurlu olduğunu düşünen bazı insanlar bile var . Java'da Thinking (şimdi 4. baskısında) olarak adlandırılan OO programlamasını ilk öğrendiğimde kullandığım çok iyi bir kitap var . Aynı yazarın C ++ için ilgili bir kitabı var. Programcılarla ilgili olarak nesne yönelimli programlamada ortak tuzaklarla uğraşan başka bir soru daha var .

Bazı tuzaklar karmaşıktır, ancak problemleri çok temel yollarla oluşturmanın birçok yolu vardır. Örneğin, birkaç yıl önce şirketimde miras aldığım bazı yazılımların ilk sürümünü yazan bir stajyer vardı ve olabilecek her şey için arayüzler yaptıbir gün birden fazla uygulamaya sahiptir. Tabii ki, vakaların% 98'inde şimdiye kadar sadece tek bir uygulama vardı, bu yüzden kod, bir arayüz çağrısına geri adım atamayacağınız için hata ayıklamayı çok can sıkıcı hale getiren kullanılmayan arabirimlerle yüklendi, böylece bir uygulama için metin araması (şimdi IntelliJ'i kullanmama rağmen "Tüm Uygulamaları Göster" özelliği vardı, ancak o günlerde buna sahip değildim). Buradaki kural prosedürel programlama ile aynıdır: her zaman bir şeyi sabit kodlayın. Sadece iki veya daha fazla şeyiniz olduğunda bir soyutlama yaratın.

Benzer bir tasarım gaflaması Java Swing API'sinde bulunabilir. Swing menü sistemi için bir yayınla-abone olun modeli kullanırlar. Bu, Swing'de menü oluşturma ve hata ayıklama işlemlerini eksiksiz bir kabus haline getirir. İroni, tamamen anlamsız olmasıdır. Birden fazla işlevin bir menü tıklamasına "abone olması" gereken neredeyse hiçbir durum yoktur. Ayrıca, yayınla-abone ol tam bir tekleme oldu çünkü bir menü sistemi normalde her zaman kullanılıyor. İşlevler abone oluyor ve ardından rastgele çıkıyor gibi değil. Sun'daki "profesyonel" geliştiricilerin böyle bir gaf yaptığı gerçeği, profesyonellerin bile OO tasarımında anıtsal vidalama yapmasının ne kadar kolay olduğunu gösteriyor.

OO programlama konusunda onlarca yıllık deneyime sahip çok uzman bir geliştiriciyim, ancak bilmediğim tonlar olduğunu ilk itiraf bile edeceğim ve şimdi bile çok fazla OO kullanma konusunda çok temkinliyim. Belirli tasarımların nasıl yapılacağı konusunda OO zealotu olan bir iş arkadaşından uzun dersler dinlerdim. Ne yaptığını gerçekten biliyordu, ama dürüst olmak gerekirse, programlarını anlamakta zorlandım çünkü böyle sofistike tasarım modelleri vardı.


1
"Netlik [verimlilikten] çok daha önemlidir" için +1
Stephen

Beni "kötü yazılmış bir OO programı" nı oluşturan bir bağlantıya yönlendirebilir veya bir düzenlemeye bununla ilgili daha fazla bilgi ekleyebilir misiniz?
Lombard

@ Lomber bunu yaptım.
Tyler Durden

1

İlk yaklaşım gayet iyi. C gibi prosedürel dillerde, standart yaklaşım işlevselliği ad alanlarına ayırmaktır - gibi statik sınıflar kullanmak DatabaseInfoGettertemelde aynı şeydir. Açıkçası bu yaklaşım, her şey yöntemlere bölünmüş olsa bile, her şeyi tek bir sınıfa itmekten daha basit, daha modüler ve daha okunabilir / bakımı kolay bir koda yol açar.

Bundan bahsetmişken, yöntemleri mümkün olduğunca az eylem gerçekleştirmeye sınırlamaya çalışın. Bazı programcılar biraz daha az ayrıntı düzeyini tercih eder , ancak devasa yöntemler her zaman zararlı olarak kabul edilir.

Hala karmaşıklıkla uğraşıyorsanız, büyük olasılıkla programınızı daha da yıkmanız gerekir. Hiyerarşide daha fazla seviye oluşturun - belki DatabaseInfoGetterbaşka sınıflara ProductTableEntryveya başka bir şeye başvurmanız gerekebilir . Yordamsal kod yazıyorsunuz ancak unutmayın, C # kullanıyorsunuz ve OOP size karmaşıklığı azaltmak için bir sürü araç sunuyor, örn:

int main() 
{
    var thisthat = Database.GetThisThat();
}

public class ThisThatClass
{
    public String This;
    public String That;
}

public static class Database 
{
    public ThisThatClass GetThisThat()
    {
        return new ThisThatClass 
        {
            This = GetThis(),
            That = GetThat()
        };
    }

    public static String GetThis() 
    { 
        //stuff
    }
    public static String GetThat() 
    { 
        //stuff
    }

}

Ayrıca, statik sınıflara dikkat edin. Veritabanı sınıfları iyi adaylardır .. genellikle bir veritabanı olduğu sürece .. fikir olsun.

Nihayetinde matematiksel işlevlerde düşünürseniz ve C # stilinize uymuyorsa, Scala, Haskell, vb.


0

Ben 4 yıl geç cevap verdim ama bir OO dilinde prosedürel şeyler yapmaya çalıştığınızda, o zaman bir antipattern üzerinde çalışıyorsunuz. Bu yapman gereken bir şey değil! Bu karşıtlığı gideren ve bunun için bir çözüm gösteren bir blog buldum, ancak çok fazla yeniden düzenleme ve zihniyet değişikliği gerektiriyor. Daha fazla bilgi için Nesneye Dayalı koddaki yordamsal kod bölümüne bakın .
"This" ve "that" dan bahsettiğiniz gibi, temelde iki farklı sınıfınız olduğunu öneriyorsunuz. A Bu sınıf (kötü ad!) Ve O sınıf. Ve örneğin bunu çevirebilirsiniz:

var summary = SummaryPageGenerator.GeneratePage(thisThing, thatThing);

bunun içine:

var summary = SummaryPageGenerator.GeneratePage(new This(DatabaseInfoGetter), new That(DatabaseInfoGetter));

Şimdi, bu 2.000+ prosedürel kod satırını görmek ve çeşitli bölümlerin ayrı sınıflarda nasıl gruplandırılacağını belirlemek ve çeşitli prosedürleri bu sınıflara taşımak ilginç olacaktır.
Her sınıf basit olmalı ve sadece bir şey yapmaya odaklanmalıdır. Ve bana öyle geliyor ki, kodun bazı bölümleri zaten üst sınıflarla uğraşıyor, bu aslında kullanışlı olamayacak kadar büyük. Örneğin, DatabaseInfoGetter kafa karıştırıcı bir yol gibi geliyor. Zaten ne oluyor? Kulağa çok genel geliyor. Ancak SummaryPageGenerator son derece spesifik! Ve PrintUtility tekrar genel.
Bu nedenle, başlangıç ​​için sınıflarınızın genel adlarından kaçınmalı ve bunun yerine daha spesifik adlar kullanmaya başlamalısınız. Örneğin, PrintUtility sınıfı, daha çok bir Header sınıfı, bir Footer sınıfı, bir TextBlock sınıfı, bir Image sınıfı ve baskıda nasıl akacaklarını göstermenin bir yolu olan bir Print sınıfı olacaktır. Yine de PrintUtility ad alanı .
Veritabanı için benzer bir hikaye. Entity Framework'ü veritabanı erişimi için kullansanız bile, kullandığınız şeylerle sınırlı olmalı ve mantıksal gruplara bölünmesini sağlamalısınız.
Ama merak ediyorum 4 yıl sonra hala bu sorunla ilgileniyor musunuz? Eğer öyleyse, o zaman "prosedürel kavramdan" ve "nesne yönelimli kavram" a değiştirilmesi gereken bir zihniyettir. Deneyiminiz yoksa zorlayıcıdır ...


-3

Bence, Basit, Tutarlı ve Okunabilir olması için kodunuzu değiştirmelisiniz.

Bu konuyla ilgili bazı blog yazıları yazdım ve güven bana anladıkları basit: İyi kod nedir

Basit: Bir devre kartı gibi, her biri sorumluluk taşıyan farklı parçalar içerir. Kod daha küçük ve basit parçalara bölünmelidir.

Tutarlı: Öğeleri ve şeyleri adlandırmak için bir standart olan desenleri kullanın. Her zaman aynı şekilde çalışan araçları seviyorsunuz ve onları nerede bulacağınızı bilmek istiyorsunuz. Kod ile aynıdır.

Okunabilir: Yazılımın hedeflediği (mattnz) alanda yaygın olarak kullanılmadığı ve bilinmediği sürece kısaltmalar kullanmayın, anlaşılır ve anlaşılması kolay belirgin adları tercih edin.


1
Kısaltmalar, yazılımın hedeflediği etki alanında yaygın olarak kullanılıyorsa ve biliniyorsa kabul edilebilir. Hava Trafik Kontrol yazılımını kullanmadan deneyin - kısaltmalardan oluşan kısaltmalar var - kimse ne hakkında konuştuğunuzu bilemezdi, tam adı kullandınız. Ağ için HTTP, otomotivde ABS gibi şeyler tamamen kabul edilebilir.
mattnz
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.