سؤال

دعونا نقول لديك فئة تسمى العميل الذي يحتوي على الحقول التالية:

  • اسم المستخدم
  • البريد الإلكتروني
  • الاسم الأول
  • الاسم الأخير

دعونا نقول أيضا أنه وفقا الأعمال التجارية الخاصة بك المنطق ، جميع العملاء الكائنات يجب أن يكون هؤلاء أربعة خصائص محددة.

الآن يمكننا القيام بذلك بسهولة جدا عن طريق إجبار منشئ تحديد كل من هذه الخصائص.ولكن من السهل جدا أن نرى كيف أن هذا يمكن أن تخرج عن السيطرة عندما كنت اضطر إلى إضافة المزيد من الحقول المطلوبة إلى وجوه العملاء.

رأيت الفئات التي تأخذ في 20+ الحجج في منشئ انها مجرد الألم إلى استخدامها.ولكن بدلا من ذلك, إذا كنت لا تحتاج إلى هذه الحقول واجهت خطر وجود معرف المعلومات ، أو أسوأ من ذلك ، كائن الرجوع الأخطاء إذا كنت تعتمد على رمز الدعوة إلى تحديد هذه الخصائص.

هل هناك أي بدائل أو هل عليك أن تقرر ما إذا كان X كمية من منشئ الحجج كثيرة جدا بالنسبة لك أن تعيش ؟

هل كانت مفيدة؟

المحلول

اثنين من تصميم مناهج النظر

على جوهر نمط

على يجيد واجهة نمط

هذه هي كل المشابهة في القصد في بناء ببطء وسيطة كائن ثم خلق هدفنا الكائن في خطوة واحدة.

مثال بطلاقة واجهة في العمل:

public class CustomerBuilder {
    String surname;
    String firstName;
    String ssn;
    public static CustomerBuilder customer() {
        return new CustomerBuilder();
    }
    public CustomerBuilder withSurname(String surname) {
        this.surname = surname; 
        return this; 
    }
    public CustomerBuilder withFirstName(String firstName) {
        this.firstName = firstName;
        return this; 
    }
    public CustomerBuilder withSsn(String ssn) {
        this.ssn = ssn; 
        return this; 
    }
    // client doesn't get to instantiate Customer directly
    public Customer build() {
        return new Customer(this);            
    }
}

public class Customer {
    private final String firstName;
    private final String surname;
    private final String ssn;

    Customer(CustomerBuilder builder) {
        if (builder.firstName == null) throw new NullPointerException("firstName");
        if (builder.surname == null) throw new NullPointerException("surname");
        if (builder.ssn == null) throw new NullPointerException("ssn");
        this.firstName = builder.firstName;
        this.surname = builder.surname;
        this.ssn = builder.ssn;
    }

    public String getFirstName() { return firstName;  }
    public String getSurname() { return surname; }
    public String getSsn() { return ssn; }    
}
import static com.acme.CustomerBuilder.customer;

public class Client {
    public void doSomething() {
        Customer customer = customer()
            .withSurname("Smith")
            .withFirstName("Fred")
            .withSsn("123XS1")
            .build();
    }
}

نصائح أخرى

أرى أن بعض الناس ينصحون سبعة باعتبارها الحد الأعلى.على ما يبدو أنه ليس صحيحا أن الناس يمكن أن تعقد الأمور السبعة في الرأس في آن واحد ؛ إلا أنها يمكن أن تذكر أربعة (سوزان Weinschenk, 100 الأمور كل مصمم يحتاج إلى معرفته عن الناس, 48).حتى لا تنظر إلى شيء من مدار الأرض.ولكن هذا بسبب تفكيري قد تم تعديلها من قبل بوب مارتن.

في رمز نظيفة, يا عم بوب يجادل لمدة ثلاثة باعتبارها العامة الحد الأعلى لعدد من المعلمات.وقال انه يجعل الراديكالية المطالبة (40):

العدد المثالي من الحجج الدالة هي صفر (niladic).ثم يأتي واحد (بعملية) تليها اثنين (الديناميكية).ثلاث حجج (الثلاثية) ينبغي تجنبها قدر الإمكان.أكثر من ثلاثة (polyadic) يتطلب خاص جدا تبرير—ثم لا ينبغي أن تستخدم على أي حال.

يقول هذا لأنه من القراءة ؛ ولكن أيضا بسبب قابلية الاختبار:

تخيل صعوبة كتابة جميع حالات الاختبار للتأكد من أن جميع تركيبات مختلفة من الحجج العمل بشكل صحيح.

أنا أشجعكم على العثور على نسخة من كتابه و قراءة كامل له مناقشة الحجج وظيفة (40-43).

أنا أتفق مع أولئك الذين ذكرت واحد المسؤولية المبدأ.فمن الصعب بالنسبة لي أن أعتقد أن الصف يحتاج إلى أكثر من يومين أو ثلاثة القيم/الكائنات بدون معقول التخلف حقا قد المسؤولية واحدة فقط و لن تكون أفضل حالا مع فئة أخرى المستخرجة.

الآن, إذا كنت بالحقن التبعيات الخاصة بك من خلال منشئ بوب مارتن الجدل حول مدى سهولة استدعاء منشئ لا تنطبق (لأن عادة ثم هناك نقطة واحدة فقط في التطبيق الخاص بك حيث كنت في سلك ، حتى يكون الإطار الذي يفعل ذلك بالنسبة لك).بيد أن المسؤولية واحدة المبدأ لا تزال ذات الصلة:مرة واحدة في فئة أربعة تبعيات أنا أعتبر أن رائحة أن به كمية كبيرة من العمل.

ومع ذلك ، كما هو الحال مع كل الأشياء في علوم الكمبيوتر ، هناك دون شك صالحة حالات وجود عدد كبير من المعلمات المنشئ.لا تتلوى التعليمات البرمجية الخاصة بك إلى تجنب استخدام عدد كبير من المعلمات ، ولكن إذا كنت لا تستخدم عدد كبير من المعلمات ، والتوقف عن إعطاء بعض من التفكير لأنها قد تعني رمز الخاص بك هو بالفعل ملتوية.

في حالتك العصا مع منشئ.المعلومات التي ينتمي العملاء و 4 مجالات هي بخير....

في حال كان لديك العديد من المطلوبة و الحقول الاختيارية منشئ ليس هو الحل الأفضل.كما @boojiboy وقال: من الصعب أن تقرأ ومن الصعب أيضا أن أكتب رمز العميل.

@معد اقترح استخدام هذا النمط الافتراضي واضعي اختياري attributs.أن الولايات الحقول قابلة للتغيير ، لكن هذه مشكلة ثانوية.

جوشوا كتلة فعالة جافا 2 أقول أنه في هذه الحالة يجب عليك أن تنظر البناء.مثال مأخوذ من كتاب:

 public class NutritionFacts {  
   private final int servingSize;  
   private final int servings;  
   private final int calories;  
   private final int fat;  
   private final int sodium;  
   private final int carbohydrate;  

   public static class Builder {  
     // required parameters  
     private final int servingSize;  
     private final int servings;  

     // optional parameters  
     private int calories         = 0;  
     private int fat              = 0;  
     private int carbohydrate     = 0;  
     private int sodium           = 0;  

     public Builder(int servingSize, int servings) {  
      this.servingSize = servingSize;  
       this.servings = servings;  
    }  

     public Builder calories(int val)  
       { calories = val;       return this; }  
     public Builder fat(int val)  
       { fat = val;            return this; }  
     public Builder carbohydrate(int val)  
       { carbohydrate = val;   return this; }  
     public Builder sodium(int val)  
       { sodium = val;         return this; }  

     public NutritionFacts build() {  
       return new NutritionFacts(this);  
     }  
   }  

   private NutritionFacts(Builder builder) {  
     servingSize       = builder.servingSize;  
     servings          = builder.servings;  
     calories          = builder.calories;  
     fat               = builder.fat;  
     soduim            = builder.sodium;  
     carbohydrate      = builder.carbohydrate;  
   }  
}  

ومن ثم استخدامها مثل هذا:

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
      calories(100).sodium(35).carbohydrate(27).build();

المثال أعلاه مأخوذة من فعالة جافا 2

و هذا لا ينطبق فقط على منشئ.نقلا عن كينت بيك في تنفيذ أنماط:

setOuterBounds(x, y, width, height);
setInnerBounds(x + 2, y + 2, width - 4, height - 4);

جعل المستطيل صريحة ككائن يفسر مدونة الأفضل:

setOuterBounds(bounds);
setInnerBounds(bounds.expand(-2));

أعتقد أن "نقية صافية" الجواب هو أنه إذا كان العمليات على فئة غير صحيحة عند بعض أفراد ليسوا تهيئة ثم هؤلاء الأعضاء يجب أن يكون منشئ.هناك دائما حالة القيم الافتراضية يمكن استخدامها ، ولكن سأفترض أننا لا تفكر في هذه الحالة.هذا هو نهج جيد عندما API هو ثابت ، لأن تغيير واحد المسموح به منشئ بعد API يذهب الجمهور سوف يكون كابوسا بالنسبة لك و لجميع المستخدمين من التعليمات البرمجية الخاصة بك.

في C#, ما أفهم عن تصميم المبادئ التوجيهية هو أن هذا ليس بالضرورة الطريقة الوحيدة للتعامل مع الوضع.لا سيما مع WPF الكائنات ، ستجد أن .صافي الطبقات تميل لصالح parameterless المنشئات سوف رمي الاستثناءات إذا لم تكن البيانات تهيئة الدولة المرغوب فيه قبل استدعاء الأسلوب.وربما هذا هو أساسا معينة إلى عناصر التصميم على الرغم ؛ أنا لا يمكن أن تأتي مع الخرسانة المثال .صافي الفئة التي يتصرف بهذه الطريقة.في الحالة الخاصة بك ، ذلك بالتأكيد يسبب زيادة العبء على اختبار للتأكد من أن فئة يتم حفظها أبدا إلى مخزن البيانات ما لم الخصائص تم التحقق من صحتها.بصراحة لأن هذا أفضل "منشئ مجموعات الخصائص المطلوبة" النهج إذا API الخاص بك هو إما تعيين في الحجر أو لا العامة.

شيء واحد أنا am المؤكد هو أن هناك على الأرجح عدد لا يحصى من المنهجيات التي يمكن أن تحل هذه المشكلة ، وكل واحد منهم يقدم مجموعة من المشاكل.أفضل شيء فعله هو تعلم العديد من أنماط ممكن واختيار أفضل واحد للحصول على الوظيفة.(أليس هذا مثل هذا الشرطي من جواب؟)

أعتقد أن سؤالك هو أكثر عن تصميم الفصول الدراسية من حول عدد من الحجج في منشئ.إذا كنت بحاجة إلى 20 قطعة من البيانات (الحجج) بنجاح تهيئة كائن ، ربما تنظر في كسر الطبقة.

ستيف ماكونيل يكتب في مدونة كاملة أن الناس لديهم صعوبة في الحفاظ على أكثر من 7 أشياء في رأسه في وقت واحد ، بحيث سيكون عدد أحاول أن أبقى تحت.

إذا كان لديك unpalatably العديد من الحجج ، ثم مجرد مجموعة منها معا في البنيات / جراب الطبقات ، ويفضل أن يكون ذلك أعلن الطبقات الداخلية من الدرجة كنت بناء.وبهذه الطريقة يمكنك لا تزال تتطلب حقول حين جعل الكود الذي يستدعي منشئ معقول للقراءة.

أعتقد أن كل هذا يتوقف على الوضع.عن شيء مثل المثال الخاص بك ، فئة العملاء لن المخاطر فرصة وجود تلك البيانات غير معروف عند الحاجة.على الجانب الآخر, تمرير البنية قد أوضح الحجة قائمة ، ولكن سوف لا يزال لديك الكثير من الأمور التي تحدد في البنية.

أعتقد أن أسهل طريقة للعثور على مقبول الافتراضي لكل قيمة.في هذه الحالة, كل حقل يبدو أنه ستكون هناك حاجة لبناء لذا ربما تفرط في استدعاء دالة بحيث إذا كان هناك شيء غير محدد في الدعوة إلى تعيين إلى الافتراضي.

ثم جعل جالبة واضعة وظائف لكل خاصية حيث أن القيم الافتراضية يمكن أن تتغير.

تنفيذ جافا:

public static void setEmail(String newEmail){
    this.email = newEmail;
}

public static String getEmail(){
    return this.email;
}

وهذا هو أيضا ممارسة جيدة للحفاظ على المتغيرات العالمية آمنة.

نمط يهم الكثير, و يبدو لي أنه إذا كان هناك منشئ مع 20+ الحجج ، ثم تصميم يجب أن تتغير.توفر معقول التخلف.

أنا أوافق على 7 البند حد Boojiboy يذكر.أبعد من ذلك ، قد يكون من المفيد النظر في مجهول (أو المتخصصة) أنواع, يقع, أو المراوغة عن طريق المفتاح الأساسي إلى مصدر بيانات آخر.

أود أن تغلف مجالات مماثلة إلى كائن من تلقاء نفسها مع البناء/التحقق من صحة المنطق.

ويقول على سبيل المثال ، إذا كنت قد حصلت على

  • BusinessPhone
  • BusinessAddress
  • HomePhone
  • HomeAddress

أود أن جعل فئة متجر الهاتف والعنوان معا مع علامة تحديد والطقس في "المنزل" أو "العمل" الهاتف/العنوان.ومن ثم الحد من 4 حقول مجرد مجموعة.

ContactInfo cinfos = new ContactInfo[] {
    new ContactInfo("home", "+123456789", "123 ABC Avenue"),
    new ContactInfo("biz", "+987654321", "789 ZYX Avenue")
};

Customer c = new Customer("john", "doe", cinfos);

التي ينبغي أن تجعل الأمر يبدو أقل مثل السباغيتي.

بالتأكيد إذا كان لديك الكثير من المجالات ، يجب أن يكون هناك نمط يمكنك استخراج هذا من شأنه أن يجعل لطيفة الوحدة من وظيفة من تلقاء نفسها.وجعل لمزيد من رمز للقراءة أيضا.

و التالي هو أيضا الحلول الممكنة:

  • انتشرت التحقق من صحة المنطق بدلا من تخزينها في فئة واحدة.التحقق من صحة عند إدخال المستخدم منها ثم التحقق مرة أخرى في طبقة قاعدة البيانات الخ...
  • جعل CustomerFactory الطبقة التي من شأنها أن تساعد علي بناء Customers
  • @مارسيو الحل هو أيضا مثيرة للاهتمام...

مجرد استخدام الافتراضي الحجج.في اللغة التي تدعم الافتراضي طريقة الحجج (PHP, على سبيل المثال) ، هل يمكن أن تفعل هذا في طريقة التوقيع:

public function doSomethingWith($this = val1, $this = val2, $this = val3)

هناك طرق أخرى لخلق القيم الافتراضية مثل اللغات التي تدعم طريقة الحمولة الزائدة.

بالطبع يمكنك أيضا تعيين القيم الافتراضية عند اعلان المجالات ، إذا كنت ترى ذلك مناسبا.

انها حقا فقط ينزل إلى ما إذا كان أو لم يكن هو المناسب لك تعيين هذه القيم الافتراضية ، أو إذا كانت الأشياء التي يجب specced في البناء في كل وقت.هذا هو حقا المقرر أن فقط يمكنك أن تجعل.

إلا إذا كان أكثر من 1 الحجة ، أنا دائما استخدام صفائف أو الكائنات منشئ المعلمات و الاعتماد على خطأ التحقق للتأكد من المعلمات المطلوبة هناك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top