Nesneye Yönelik Programlama: getters / setters veya logical names


12

Şu anda yazdığım bir sınıfa bir arayüz düşünüyorum. Bu sınıf, bir karakterin stillerini içerir, örneğin karakterin kalın, italik, altı çizili vb. Olup olmadığını iki gün boyunca kendimle tartışıyorum. Değerleri değiştiren yöntemler için getters / setters veya mantıksal isimler kullanmalı bu stiller. Mantıksal isimleri tercih etme eğilimim olsa da, bu kadar verimli ve mantıksal olmayan kod yazmak anlamına gelir. Sana bir örnek vereyim.

Bir sınıf var CharacterStylesüye değişkenleri vardır bold, italic, underline(ve bazı diğerleri, ama basit tutmak onları bırakacağım). Programın diğer bölümlerinin bu değişkenlere erişmesine izin vermenin en kolay yolu getter / setter yöntemlerini yazmaktır, böylece styles.setBold(true)ve yapabilirsiniz styles.setItalic(false).

Ama bundan hoşlanmıyorum. Sadece bir çok insan getters / setter'ların kapsüllemeyi kırdığını söyledikleri için değil (gerçekten bu kadar kötü mü?), Ama çoğunlukla bana mantıklı gelmediği için. Bir karakteri bir yöntemle styles.format("bold", true)ya da bunun gibi bir şeyle stilize etmeyi umuyorum, ancak tüm bu yöntemlerle değil.

Yine de bir sorun var. Bir nesne üyesi değişkeni C ++ 'da bir dizenin içeriğine göre erişemediğiniz için, tüm stiller için büyük bir if-deyimi / anahtar kapsayıcısı yazmak zorunda kalacağım veya stilleri ilişkilendirilebilir bir dizide ( ) map.

En iyi yolun ne olduğunu bulamıyorum. Sanırım bir an getters / setters yazmalıyım ve bir sonraki an diğer tarafa doğru eğildim. Sorum şu: ne yapardın? Bunu neden yaptın?


CharacterStyles sınıfı aslında üç boolean demeti dışında bir şey yapıyor mu? Nasıl tüketilir?
Mark Canlas

Evet, çünkü CharacterStyles diğer CharacterStyles öğelerinden miras alabilmelidir. Diğer bir deyişle, boldayarlanmış bir CharacterStyles varsa trueve diğer değişkenler tanımsızsa, diğer değişkenler için getter yöntemlerinin üst stilin değerini (başka bir özellikte depolanır) bolddöndürmesi gerekirken , özellik için getter dönmelidir true. Bir isim ve arayüzde görüntülenme şekli gibi başka şeyler de var.
Kurbağa

Çeşitli stil seçeneklerini tanımlamak için bir numaralandırma kullanabilir, ardından bir switch ifadesi kullanabilirsiniz. Btw, undefined ile nasıl başa çıkıyorsunuz?
Tyanna

@Tyanna: Gerçekten de, bir numaralandırma kullanmayı düşündüm, ama bu sadece küçük bir ayrıntı. NULL olarak tanımsız değerleri ayarlamayı planlıyordum. Bu en iyi yol değil mi?
Kurbağa

Yanıtlar:


6

Evet, alıcılar / ayarlayıcılar kapsülleme işlemini kırıyor - temelde doğrudan temel alana erişim arasında sadece ekstra bir katman. Sadece doğrudan erişebilirsiniz.

Şimdi, alana erişmek için daha karmaşık yöntemler istiyorsanız, bu geçerlidir, ancak alanı ortaya koymak yerine, sınıfın hangi yöntemleri sunması gerektiğini düşünmeniz gerekir. yani. bir özelliği kullanarak Money değerine sahip bir Bank sınıfı yerine, bir Bank nesnesinin ne tür erişim sunması gerektiğini (para ekleyin, para çekme, bakiye alma) düşünün ve bunları uygulayın. Money değişkenindeki bir özellik yalnızca Money değişkenini doğrudan göstermekten sözdizimsel olarak farklıdır.

DrDobbs'un daha fazlasını söyleyen bir makalesi var.

Senin sorunun için, olası stilleri bir numara almak setStyle ve clearStyle (ya da ne olursa olsun) 2 yöntem olurdu. Bu yöntemlerin içindeki bir switch deyimi, ilgili değerleri uygun sınıf değişkenlerine uygular. Bu şekilde, daha sonra (örneğin HTML kullanım için) bir dize olarak depolamak karar verirseniz başka bir şeye stilleri iç temsilini değiştirebilir - bir şeymiş senin sınıfın tüm kullanıcıları gerektiren değiştirilmesi kullandığınız takdirde çok alma / ayarlama özellikleri.

Rastgele değerler almak, büyük bir if-then deyimine sahipseniz (bunlardan birkaçı varsa) veya std :: mem_fun (veya std :: kullanarak yöntem işaretçileri için dize değerlerinin bir haritası varsa, dizeleri açabilirsiniz. işlevi ) bu nedenle "kalın" değeri, bir değer anahtarını sts :: mem_fun olacak şekilde, kalın değişkenini true olarak ayarlayan bir yönteme kaydedilir (dizeler üye değişken adlarıyla aynıysa, yazmanız gereken kod miktarını azaltmak için dizgi oluşturucu makro )


Mükemmel cevap! Özellikle verilerin HTML olarak depolanmasına ilişkin kısım, bu yolda ilerlemem için iyi bir neden olarak beni etkiledi. Bu yüzden farklı stilleri bir numarada depolamanızı ve sonra styles.setStyle(BOLD, true)? Bu doğru mu?
Kurbağa

evet, sadece 2 yöntemim olurdu - setStyle (BOLD) ve clearstyle (BOLD). 2. parametreyi unut, ben sadece böyle tercih ve daha sonra tüm stil bayraklarını temizlemek için hiçbir parametre almak için clearStyle aşırı yükleyebilirsiniz.
gbjbaanb

Bu işe yaramaz, çünkü bazı türlerin (yazı tipi boyutu gibi) bir parametreye ihtiyacı vardır. Ama yine de cevap için teşekkürler!
Kurbağa

Bunu uygulamaya çalışıyorum, ancak düşünmediğim bir sorun var: styles.getStyle(BOLD)sadece boolean türünde üye değişkenlere sahip değil, aynı zamanda tamsayı ve dize türlerine (örneğin:) sahip olduğunuzda nasıl uygularsınız styles.getStyle(FONTSIZE). İade türlerini aşırı yükleyemediğiniz için, bunu nasıl programlıyorsunuz? Geçersiz işaretçiler kullanabileceğinizi biliyorum, ama bu bana çok kötü geliyor. Bunun nasıl yapılacağına dair ipuçlarınız var mı?
Kurbağa

bir birleşim veya bir yapı döndürebilir veya yeni standartla, iade türüne göre aşırı yükleyebilirsiniz. Bununla birlikte, bir stil ayarlamak için tek bir yöntem uygulamaya mı çalışıyorsunuz, stilin bir bayrak, bir yazı tipi ailesi ve bir boyut olduğu? Belki de bu durumda soyutlamayı biraz fazla zorlamaya çalışıyorsunuzdur.
gbjbaanb

11

Düşünmediğiniz bir fikir Dekoratör Kalıbıdır . Bir nesnede bayraklar ayarlamak ve yazdığınız her şeye bu bayrakları uygulamak yerine, yazıyı yapan sınıfı Dekoratörler'e sarırsınız, bu da stilleri uygular.

Arama kodunun, metninizin etrafına bu sarmalayıcılardan kaçını koyduğunuzu bilmesine gerek yoktur, sadece dış nesnede bir yöntem çağırırsınız ve yığını yığar.

Bir sözde kod örneği için:

class TextWriter : TextDrawingInterface {
    public:
        void WriteString(string x) {
            // write some text somewhere somehow
        }
}

class BoldDecorator : TextDrawingInterface {
    public:
        void WriteString(string x) {
            // bold application on
            m_textWriter.WriteString(x);
            // bold application off
        }

        ctor (TextDrawingInterface textWriter) {
            m_textWriter = textWriter;
        }

    private:
        TextWriter m_TextWriter;
}

Ve böylece, her dekorasyon stili için. En basit kullanımında şunu söyleyebilirsiniz:

TextDrawingInterface GetDecoratedTextWriter() {
    return new BoldDecorator(new ItalicDecorator(new TextWriter()));
}

Ve bu yöntemi çağıran kodun, ne aldığını ayrıntılarıyla bilmesine gerek yok. Bir WriteString yöntemiyle metin çizebilen SOMETHING olduğu sürece.


Hmmm, yarına yeni bir zihinle bakacağım ve o zaman sana geri döneceğim. Cevap için teşekkürler.
Kurbağa

Dekoratör deseninin büyük bir hayranıyım. Bu kalıbın HTML'ye benzemesi (burada çekirdek işlem giriş dizesini etiketlerle kapsamaktır), bu yaklaşımın tüm arayüz kullanıcılarınızın ihtiyaçlarını karşılayabileceğinin bir kanıtıdır. Akılda tutulması gereken bir şey, iyi ve kullanımı kolay bir arayüzün teknik olarak karmaşık olan temel bir uygulamaya sahip olabileceğidir. Aslında kendine işleyici metin uyguladıklarını Örneğin, sen bulabilirsiniz TextWriterhem konuşmak ihtiyaçları BoldDecoratorve ItalicDecorator(iki yönlü) işin yapılması için.
rwong

bu güzel bir cevap olsa da, op'un sorusunu yeniden tanıtmıyor mu? "cesur uygulama" -> bu nasıl yapılacak? SetBold () gibi setters / getters kullanıyor musunuz? Bu tam olarak op'un sorusudur.
stijn

1
@stijn: Pek değil. Bu durumdan kaçınmanın birkaç yolu vardır. Örneğin, bir oluşturucuya bir diziden dekoratörler ekleyen ve kaldıran bir toggleStyle yöntemiyle (enum argümanı) sarabilirsiniz, yalnızca BuildDecoratedTextWriter'ı çağırdığınızda son öğeyi süslersiniz. Ya da rwong'un önerdiği gibi yapabilir ve temel sınıfı karmaşıklaştırabilirsiniz. Duruma göre değişir ve OP, hangisinin en iyi olduğunu tahmin etmek için genel spesifikasyon hakkında yeterince spesifik değildi. Yine de deseni aldığında anlayabilecek kadar akıllı görünüyor.
pdr

1
Her zaman Dekoratör Deseninin dekorasyonlara bir sipariş verdiğini düşündüm. Gösterilen örnek kodu ele alalım; ItalicDecorator'ı nasıl kaldırabilirim? Yine de, Dekoratör gibi bir şeyin gitmenin yolu olduğunu düşünüyorum. Kalın, italik ve altı çizili yalnızca üç stil değildir. İnce, yarı kalın, yoğun, siyah, geniş, eğik italik, küçük kapaklar, vb. Vardır. Bir karaktere keyfi olarak büyük bir stil seti uygulamak için bir yol gerekebilir.
Barry Brown

0

İkinci çözüme doğru eğilirdim. Daha zarif ve esnek görünüyor. Kalın, italik ve altı çizili (üst çizgi?) Dışında başka türler hayal etmek zor olsa da, üye değişkenleri kullanarak yeni türler eklemek zor olacaktır.

Bu yaklaşımı en son projelerimden birinde kullandım. Birden çok boolean öznitelikleri olabilir bir sınıf var. Özelliklerin sayısı ve adları zaman içinde değişebilir. Onları bir sözlükte saklıyorum. Bir öznitelik yoksa değerinin "false" olduğunu varsayarım. Ayrıca mevcut özellik adlarının bir listesini de saklamalıyım, ancak bu başka bir hikaye.


1
Bu türlerin dışında üstü çizili, yazı tipi boyutu, yazı tipi ailesi, üst simge, alt simge ve belki de daha sonra diğerleri ekleyeceğim. Ama neden projenizde bu yöntemi seçtiniz? İzin verilen özelliklerin bir listesini saklamanın kirli kod olduğunu düşünmüyor musunuz? Bu sorulara verdiğiniz yanıtların ne olduğunu gerçekten merak ediyorum!
Kurbağa

Uygulama zaten dağıtıldığında bazı özniteliklerin müşteriler tarafından tanımlanabileceği durumla uğraşmak zorunda kaldım. Bazı müşteriler için bazı diğer özellikler gerekliydi, ancak diğerleri için kullanılmıyor. Formları, depolanan veri kümelerini özelleştirebilir ve bu yaklaşımı kullanarak diğer sorunları çözebilirim. Kirli kod oluşturduğunu sanmıyorum. Bazen müşteriniz için ne tür bilgilere ihtiyaç olacağını tahmin edemezsiniz.
Andrzej Bobak

Ancak müşterimin özel özellikler eklemesine gerek kalmayacak. Ve bu durumda sanırım biraz "çılgın" görünüyor. Kabul etmiyor musun?
Frog

Dinamik sayıda öznitelik sorunuyla karşılaşmazsanız, bunları depolamak için esnek alana ihtiyacınız yoktur. Bu doğru :) Yine de diğer kısmı kabul etmiyorum. Bence sözlük / hashmap / etc'deki stroring öznitelikleri kötü bir yaklaşım değildir.
Andrzej Bobak

0

Bence bu konuyu çok fazla düşünüyorsun.

styles.setBold(true) ve styles.setItalic(false)iyi

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.