سؤال

الجديد امتداد في .Net framework 3.5 تسمح وظيفة تقسيم من الواجهات.

فعلى سبيل المثال في .Net 2.0

public interface IHaveChildren {
    string ParentType { get; }
    int ParentId { get; }

    List<IChild> GetChildren()
}

يمكن (3.5) تصبح:

public interface IHaveChildren {
    string ParentType { get; }
    int ParentId { get; }
}

public static class HaveChildrenExtension {
    public static List<IChild> GetChildren( this IHaveChildren ) {
        //logic to get children by parent type and id
        //shared for all classes implementing IHaveChildren 
    }
}

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

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

أي أسباب أخرى لا تستخدم بانتظام هذا النمط ؟


التوضيح:

نعم, لقد رأيت اتجاه مع طرق الإرشاد هو في نهاية المطاف معهم في كل مكان.أود أن تكون حذرا لا سيما وجود أي على .صافي القيمة أنواع من استعراض الأقران (أعتقد ان الوحيد الذي يجب على سلسلة هو .SplitToDictionary() - مماثلة .Split() ولكن أخذ قيمة المفتاح محدد جدا)

أعتقد أن هناك أفضل الممارسات النقاش هناك؛ -)

(بالمناسبة:DannySmurf ، مساء أصوات مخيفة.)

أنا أسأل تحديدا عن استخدام أساليب الإرشاد حيث في السابق كان لدينا أساليب واجهة.


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

هذا ما MS فعل IEnumerable IQueryable عن Linq?

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

المحلول

أعتقد أن الاستخدام الحكيم امتداد طرق وضع واجهات على المزيد من equatable الموقف مع (مجردة) قاعدة الطبقات.


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

كمثال ملموس ، النسخة الأولى من مكتبة يمكن تعريف واجهة مثل ذلك:

public interface INode {
  INode Root { get; }
  List<INode> GetChildren( );
}

مرة واحدة المكتبة أصدرت لا يمكننا تعديل واجهة دون كسر المستخدمين الحاليين.بدلا من ذلك, في الإصدار القادم سوف تحتاج إلى تحديد واجهة جديدة لإضافة مزيد من functionalty:

public interface IChildNode : INode {
  INode Parent { get; }
}

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

public static class NodeExtensions {
  public INode GetParent( this INode node ) {
    // If the node implements the new interface, call it directly.
    var childNode = node as IChildNode;
    if( !object.ReferenceEquals( childNode, null ) )
      return childNode.Parent;

    // Otherwise, fall back on a default implementation.
    return FindParent( node, node.Root );
  }
}

الآن لجميع مستخدمي المكتبة الجديدة يمكن علاج والقديمة على حد سواء الحديثة تطبيقات مماثل.


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

بدلا امتداد طرق يمكن استخدامها لتوفير تافهة الزائد تطبيقات:

public interface ILongMethod {
  public bool LongMethod( string s, double d, int i, object o, ... );
}

...
public static LongMethodExtensions {
  public bool LongMethod( this ILongMethod lm, string s, double d ) {
    lm.LongMethod( s, d, 0, null );
  }
  ...
}


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


تحرير: ذات وظيفة جو دافي: أساليب الإرشاد كما الافتراضي واجهة تطبيقات أسلوب

نصائح أخرى

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

مرة واحدة في كائن آخر يحاول استخدام بمد واحد ، لن نرى امتداد و قد reimplement/إعادة الرجوع إليها مرة أخرى.

الحكمة التقليدية هي أن أساليب الإرشاد يجب أن تستخدم فقط:

  • دروس المرافق ، Vaibhav ذكر
  • تمديد مختومة 3rd الطرف واجهات برمجة التطبيقات

أعتقد أن أفضل شيء أن أساليب الإرشاد استبدال كل تلك المرافق الفئات التي تجد في كل مشروع.

على الأقل حتى الآن, أشعر أن أي استخدام آخر من أساليب الإرشاد من شأنه أن يسبب الارتباك في مكان العمل.

بلدي اثنين بت.

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

على سبيل المثال:

namespace Model
{
    class Person
    {
        public string Title { get; set; }
        public string FirstName { get; set; }
        public string Surname { get; set; }
    }
}

namespace View
{
    static class PersonExtensions
    {
        public static string FullName(this Model.Person p)
        {
            return p.Title + " " + p.FirstName + " " + p.Surname;
        }

        public static string FormalName(this Model.Person p)
        {
            return p.Title + " " + p.FirstName[0] + ". " + p.Surname;
        }
    }
}

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

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

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

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

أما بالنسبة للسؤال:أن تكون سلعة من القيود عندما تفعل هذا - على سبيل المثال في الرمز المبين ، وذلك باستخدام طريقة التمديد لتنفيذ GetChildren بشكل فعال 'الأختام' هذا التنفيذ لا تسمح لأي IHaveChildren impl لتوفير الخاصة إذا لزم الأمر.إذا كان هذا هو موافق ، ثم أنا لا أمانع تمديد نهج الأسلوب كثيرا.لم يتم تعيين في الحجر ، وعادة ما يمكن أن يكون بسهولة بتعميل الترميز عند أكثر المرونة في وقت لاحق.

من أجل مزيد من المرونة في استخدام نمط استراتيجية قد يكون من الأفضل.شيء من هذا القبيل:

public interface IHaveChildren 
{
    string ParentType { get; }
    int ParentId { get; }
}

public interface IChildIterator
{
    IEnumerable<IChild> GetChildren();
}

public void DefaultChildIterator : IChildIterator
{
    private readonly IHaveChildren _parent;

    public DefaultChildIterator(IHaveChildren parent)
    {
        _parent = parent; 
    }

    public IEnumerable<IChild> GetChildren() 
    { 
        // default child iterator impl
    }
}

public class Node : IHaveChildren, IChildIterator
{ 
    // *snip*

    public IEnumerable<IChild> GetChildren()
    {
        return new DefaultChildIterator(this).GetChildren();
    }
}

أكثر قليلا.

إذا واجهات متعددة لها نفس طريقة التمديد التوقيع, سوف تحتاج إلى صراحة تحويل المتصل إلى واجهة واحدة نوع ومن ثم استدعاء الأسلوب.E. g.

((IFirst)this).AmbigousMethod()

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

هذا هو السبب الذي يعلن دائما واجهة النوع بدلا من الدرجة الفعلية.

IInterface variable = new ImplementingClass();

أليس كذلك ؟

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

روب كونري (دون سرعة الصوت و MVC واجهة) نفذت IRepository مثل نمط في واجهة التطبيق.انها ليست تماما نمط أعلاه ، ولكنها لا تبادل بعض أوجه التشابه.

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

وليس النهج التقليدي ، ولكن بارد جدا و بالتأكيد حالة جافة.

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

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

أنا بحاجة إلى حل شيء مماثل:أردت أن يكون لديك قائمة<IIDable> مرت على امتداد وظيفة حيث IIDable هو واجهة طويل getId() وظيفة.حاولت استخدام GetIds(هذه القائمة<IIDable> bla) لكن المترجم لم تسمح لي بذلك.لقد استخدمت قوالب بدلا من ذلك ثم اكتب مسبوك داخل الدالة على نوع واجهة.أنا في حاجة هذه الوظيفة لبعض linq to sql التي تم إنشاؤها الطبقات.

آمل أن يساعد هذا :)

    public static List<long> GetIds<T>(this List<T> original){
        List<long> ret = new List<long>();
        if (original == null)
            return ret;

        try
        {
            foreach (T t in original)
            {
                IIDable idable = (IIDable)t;
                ret.Add(idable.getId());
            }
            return ret;
        }
        catch (Exception)
        {
            throw new Exception("Class calling this extension must implement IIDable interface");
        }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top