Bir yapıcıyı nasıl parçalayabilirsiniz?


21

Diyelim ki bir Düşman dersim var ve kurucu şöyle bir şeye benzeyecek:

public Enemy(String name, float width, float height, Vector2 position, 
             float speed, int maxHp, int attackDamage, int defense... etc.){}

Bu kötü görünüyor, çünkü yapıcının çok fazla parametresi var, ancak bir Düşman örneği oluşturduğumda bunların hepsini belirtmem gerekiyor. Ayrıca, bu özellikleri Düşman sınıfında da istiyorum, böylece onların bir listesini tekrarlayabilir ve bu parametreleri alabilir / ayarlayabilirim. EnHantemlerini EnemyB, EnemyA sınıflarına girmeyi düşündüm, maxHp'lerini ve diğer spesifik nitelikleri kodlarken kodlamıyordu, ancak daha sonra bir EnemyA's, EnemyB's, ve EnemyA'nın oluşturduğu bir Düşman listesi ile yinelemek istersem sabit kodlu özelliklerine erişimini kaybediyordum. EnemyC en).

Sadece kodlamayı nasıl temizleyeceğimi öğrenmeye çalışıyorum. Fark yaratırsa, Java / C ++ / C # ile çalışıyorum. Doğru yönde herhangi bir nokta takdir edilmektedir.


5
Tüm özellikleri bağlayan bir kurucuya sahip olmanın kötü bir tarafı yoktur. Aslında, bazı kalıcılık ortamlarında, bu gereklidir. Hiçbir şey, birden fazla kurucuya sahip olamayacağınızı söyleyemez, belki de parça bazında inşaat yapıldıktan sonra çağrılacak olan geçerlilik kontrol yöntemiyle.
BobDalgleish

1
Enlem nesnelerini kod yazarken değişmez kullanarak inşa etmek isteyip istemediğinizi sormalıyım. Eğer yapmazsanız ve neden olduğunu görmüyorsanız, o zaman veriyi bir veritabanı arayüzünden çeken yapıcılar veya bir seri hale getirme dizgisi veya ...
Zan Lynx


Yanıtlar:


58

Çözüm, parametreleri kompozit tiplerde bir araya getirmektir. Genişlik ve Yükseklik kavramsal olarak ilişkilidir - düşmanın boyutlarını belirler ve genellikle birlikte ihtiyaç duyulacaktır. Bir türle Dimensionsveya belki Rectanglede konumu içeren bir türle değiştirilebilirler. Öte yandan, özellikle ivme sonradan resme girerse, gruplandırmak positionve speedbir MovementDatatüre ayırmak daha anlamlı olabilir . Ben varsayalım bağlam itibaren maxHp, attackDamage, defensevb aynı zamanda bir de birbirine ait Statstip. Bu nedenle, gözden geçirilmiş bir imza şöyle görünebilir:

public Enemy(String name, Dimensions dimensions, MovementData movementData, Stats stats)

Çizgilerin nerede çizileceğine ilişkin ince ayrıntılar, kodunuzun geri kalan kısmına ve hangi verilerin birlikte sıkça kullanıldığına bağlı olacaktır.


21
Ayrıca, bu kadar çok değere sahip olmanın Tek Sorumluluk İlkesi'nin ihlal edildiğini gösterebileceğini de eklerdim. Değerleri belirli nesnelere gruplamak, bu sorumlulukları ayırmak için ilk adımdır.
Öforik

2
Değer listesinin bir SRP sorunu olduğunu sanmıyorum; Bunların çoğu muhtemelen temel sınıf yapıcılar için tasarlanmıştır. Hiyerarşideki her sınıfın tek bir sorumluluğu olabilir. Enemysadece hedefi hedefleyen sınıftır Player, ancak ortak temel sınıflarının Combatantmücadele istatistiklerine ihtiyacı var.
MSalters

@ MSalters Bir SRP problemini göstermesi gerekmez, ancak olabilir. Yeterli sayıda egzersizi yapması gerekiyorsa, bu işlevler statik / serbest işlevler olması gerektiğinde ( düz eski veri kapları kullanıyorsa Dimensions/ MovementDataeski düz veri kapları kullanıyorsa) veya yöntemler (bunları soyut verilere dönüştürürse) Düşman sınıfına girme yolunu bulabilir. türleri / nesne). Örnek olarak, daha önce bir Vector2tür yaratmamış olsaydı, vektör matematiği yapmış olabilir Enemy.
Doval

24

Oluşturucu düzenine bakmak isteyebilirsiniz . Bağlantıdan (alternatif ve modellerin örnekleri ile):

[]] Oluşturucu deseni, kurucuları veya statik fabrikaları bir avuç değerden fazla olan sınıfları tasarlarken, özellikle de bu parametrelerin çoğu isteğe bağlıysa, iyi bir seçimdir. Müşteri kodu, inşaatçılar ile okumak ve yazmak için geleneksel teleskopik kurucu düzeninden çok daha kolaydır ve inşaatçılar JavaBeans'tan çok daha güvenlidir.


4
Kısa kod pasajı yardımcı olabilir. Bu, çeşitli girdilere sahip karmaşık nesneler veya yapılar oluşturmak için mükemmel bir kalıptır. Oluşturucuları, EnemyABuilder, EnemyBBuilder, vb. Gibi çeşitli paylaşılan özellikleri içine alan uzmanlaştırabilirsiniz. Bu, Fabrika modelinin kapak kısmı gibidir (aşağıda cevaplandığı gibi), fakat benim kişisel tercihim Oluşturucu için.
Rob

1
Teşekkürler, hem Oluşturucu kalıbı hem de Fabrika kalıbı, genel olarak yapmaya çalıştığım şeyle iyi çalıştıkları gibi görünüyor. Yapıcı / Fabrika ve Doval'ın önerisinin bir birleşimi aradığım şey olabilir. Düzenleme: Sanırım sadece bir cevabı işaretleyebilirim; Konu sorusunu cevapladığından beri Doval'a vereceğim, ancak diğerleri de benim kendi sorunum için aynı derecede yardımcı oluyor. Hepinize teşekkür ederim.
Travis,

Diliniz hayali türleri destekliyorsa, SetX işlevlerinin bazılarının / hepsinin çağrılmasını zorlayan bir oluşturucu desen yazabileceğinize dikkat edin. Aynı zamanda bir kişinin (yalnızca istenirse) bir kez daha aranmalarını sağlar.
Thomas Eding

1
@ Mark16 Bağlantıda belirtildiği gibi, > Oluşturucu deseni, Ada ve Python'da bulunan isteğe bağlı adlandırılmış parametreleri simüle eder. Söz konusu C # ' yı da kullandığınızdan bahsettiniz ve bu dil , / isteğe bağlı argümanları (C # 4.0'dan itibaren) desteklediğinden, başka bir seçenek olabilir.
Bob

5

Bazı değerleri önceden ayarlamak için alt sınıfları kullanmak istenmez. Yalnızca yeni bir düşman türü farklı davranış veya yeni özelliklere sahip olduğunda alt sınıf.

Fabrika deseni genellikle kullanılan kesin sınıfı üzerinde soyut için kullanılır, ama aynı zamanda nesne oluşturma için şablonlar sağlamak için kullanılabilir:

class EnemyFactory {

    // each of these methods is essentially a template for a kind of enemy

    Enemy enemyA(String name, ...) {
        return new Enemy(name, ..., presetValue, ...);
    }

    Enemy enemyB(String name, ...) {
        return new Enemy(name, ..., otherValue, ...);
    }

    Enemy enemyC(String name, ...) {
        return new EnemySubclass(name, ..., otherValue, ...);
    }

    ...
}

EnemyFactory factory = new EnemyFactory();
Enemy a = factory.enemyA("fred", ...);
Enemy b = factory.enemyB("willy", ...);

0

Bağımsız olarak kullanmak isteyebileceğiniz nesneyi temsil eden sınıflara, örneğin sadece düşmanların isim, hız, maxHp veya genişlikli ekranda varlıkları olan spritleri temsil eden bir sınıfın bulunduğu bir karakter sınıfına, alt sınıflamayı ayırırdım. yükseklik, pozisyon

Çok fazla giriş parametresi olan bir yapıcıda yanlış bir şey görmüyorum, ancak onu biraz bölmek istiyorsanız, parametrelerin çoğunu ayarlayan bir yapıcı ve kullanılabilecek başka bir (aşırı yüklenmiş) yapıcınız olabilir. belirli olanları ayarlamak ve başkalarını varsayılan değerlere ayarlamak için.

Hangi dili kullanacağınıza bağlı olarak, bazıları aşağıdaki gibi yapıcınızın giriş parametreleri için varsayılan değerler ayarlayabilir:

Enemy(float height = 42, float width = 42);

0

Rory Hunter'ın cevabına eklenecek bir kod örneği (Java'da):

public class Enemy{
   private String name;
   private float width;
   ...

   public static class Builder{
       private Enemy instance;

       public Builder(){
           this.instance = new Enemy();
       }


       public Builder withName(String name){
           instance.name = name;
           return this;
       }

       ...

       public Enemy build(){
           return instance;
       }
   }
}

Şimdi, bunun gibi yeni Düşman örnekleri oluşturabilirsiniz:

Enemy myEnemy = new Enemy.Builder().withName("John").withX(x).build();

1
Programcılar turdaki kavramsal sorulardır ve cevapların bir şeyler açıklaması beklenir . Açıklama yerine kod dökümlerini atmak, kodu IDE'den beyaz tahtaya kopyalamak gibidir: tanıdık gelebilir ve hatta bazen anlaşılabilir görünebilir, ancak garip ... sadece garip geliyor. Beyaz tahta derleyici yok
gnat
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.