2015-08-31 1 views
0

EDIT Ive перефразировать вопрос, так что лучше отражает то, что им пытаются сделатьКак удалить дублирование кода при реализации интерфейсов, которые совместно используют общие методы

Я пытаюсь создать набор классов, которые все унаследует от 1 «суперкласс» или «базовый класс».

Однако я ищу способ реализовать код для каждого метода, в каждом отдельном классе, так как кажется, что это много дублирования.

Вот супер класс:

public abstract class WebObject 
{ 
    string Id { get; set; } 
    string Name { get; set; } 

    public void Click() { Console.WriteLine("Clicking object"); } 
    public string GetAttribute() { return "An attribute"; } 
    public void SetAttribute(string attribute, string value) 
    { 
     //code to set attribute 
    } 
} 

Я также создал несколько интерфейсов:

interface IReadable 
{ 
    string GetText(); 
} 

interface IWriteable 
{ 
    void SetText(string value); 
} 

Вот пример производный класс:

public class TextBox: WebObject, IWriteable, IReadable 
{ 


} 

Конечно приведенный выше класс содержит ошибку. Он не реализует IWriteable или IReadable.

Так что я мог бы сделать что-то вроде:

public class TextBox: WebObject, IWriteable, IReadable 
{ 
    public void SetText(string value) 
    { 
     //Implemented code 
    } 

    public string GetText() 
    { 
     //Implemented code 
     return "some value"; 
    } 
} 

Какой бы компилировать штраф ... Однако проблема здесь заключается в том, что SetText и GetText содержат много кода. Я не хочу копировать это каждый раз, когда хочу реализовать этот метод. Id, а просто написать код один раз и вызвать его в любое время, когда мне нужно использовать этот метод.

Я знаю, что мы не можем много наследовать на C# и Java. Так что моя оригинальная мысль была просто создать набор статических классов с кодом для SetText и GetText Показанные здесь:

public static class Setter 
{ 
    public static void SetText(string value) 
    { 
     //Code to set text 
    } 
} 

public static class Getter 
{ 
    public static string GetText() 
    { 
     //Code to get text 
     return ""; 
    } 
} 

Затем меняющегося мой класс TextBox к следующему:

public class TextBox: WebObject, IWriteable, IReadable 
{ 
    public void SetText(string value) 
    { 
     Setter.SetText(value); 
    } 

    public string GetText() 
    { 
     return Getter.GetText(); 
    } 
} 

Я не могу помочь, но чувствую, что это довольно длинное ветреное решение. Он выполняет то, что я хочу в том, что TextBox имеет ванильные методы, плюс 2 он реализует сам.

Но мой вопрос: могу ли я достичь той же цели, используя более сжатый дизайн?

Сноски

Каждый объект фактически реализует несколько общих методов. Возьмите TextBox, ComboBox и SelectBox, все они должны иметь возможность SetText, однако только CombBox и SelectBox должны иметь возможность использовать Select.

+0

Это не сработает, если вы достигнете какого-либо состояния. – SLaks

+0

Что делают 'SetText' и' GetText'? Если у вас есть статическая реализация для них, зачем вам нужны методы экземпляра, которые делают то же самое? – Blorgbeard

+0

Возможно, вы можете переместить часть своего кода в проект на C++. Там вы можете иметь множественное наследование и выставлять интерфейсы ... – Caverna

ответ

3

Чистейший способ сделать то, что вы просите, чтобы реализовать protected вспомогательных методы в рамках базового класса, который разлагает проблему «много дублирования» на более мелкие куски, которые могут быть составлены в вашей конкретных реализациях методы, как это :

public abstract class WebObject { 
    protected void SetTextImpl() { /* Implementation */ } 
    protected void GetTextImpl() { /* Implementation */ } 
} 

Тогда в ваших производных классов, реализовать только применимые интерфейсы и соответствующие методы:

public class TextBox: WebObject, IWriteable, IReadable { 
    public void SetText() { SetTextImpl(); } 
    public void GetText() { GetTextImpl(); } 
} 

public class Span: WebObject, IReadable { 
    public void GetText() { GetTextImpl(); } 
} 

Если вы знаете, что все подклассы будут IReadable Можно упростить далее:

public abstract class WebObject : IReadable { 
    protected void SetTextImpl() { /* Implementation */ } 
    protected void GetTextImpl() { /* Implementation */ } 

    // Implement IReadable -- this could be combined with GetTextImpl() but 
    // is implemented separately for consistency. 
    public void GetText() { GetTextImpl(); } 
} 

public class TextBox: WebObject, IWriteable { 
    public void SetText() { SetTextImpl(); } 
} 

public class Span: WebObject, IReadable { 
} 
+0

Я предпочитаю это решение больше всего. Он выглядит намного чище. – Festivejelly

3

Если код для этих двух методов всегда будет такой же или почти то же самое, вы могли бы создать еще один абстрактный класс (например: WebObjectReadWrite), который наследуется от WebObject и реализует интерфейс.

public abstract class WebObjectReadWrite : WebObject, IReadable, IWritable 
{ 
    // Could be made virtual if some subclasses need to overwrite default implementation. 
    public void Read() 
    { 
     // Implementation 
    } 

    // Could be made virtual if some subclasses need to overwrite default implementation. 
    public void Write() 
    { 
     // Implementation 
    } 
} 

public class TextBox : WebObjectReadWrite 
{ 
} 

Это может, однако, привести к нескольким проблемам наследования или отношениям наследования, которые не имеют смысла. Другой вариант - использовать strategy pattern (в пути) для делегирования операций чтения/записи другим классам, которые могут быть повторно использованы.

public class TextBox : WebObject, IReadable, IWriteable 
{ 
    private IReadable _readable = new TextReader(); 
    private IWriteable _writeable = new TextWriter(); 

    public void Read() 
    { 
     _readable.Read(); 
    } 

    public void Write() 
    { 
     _writable.Write(); 
    } 
} 

public class Span : WebObject, IReadable 
{ 
    // Reused class. 
    private IReadable _readable = new TextReader();   

    public void Read() 
    { 
     _readable.Read(); 
    } 
} 

public class TextReader : IReadable 
{ 
    public void Read() 
    { 
     // Reusable implementation 
    } 
} 

Это не совсем шаблон стратегии, потому что вы не позволяет вызывающему абоненту выбрать реализацию IReadable и IWriteable. Однако это позволяет вам повторно использовать классы IReadable и IWriteable.

+1

Второй предоставленный вариант достаточно близко к тому, что я бы предложил сам. Создайте новый класс/интерфейс, который выполняет settext/gettext и вводит его экземпляр в каждый класс, который нуждается в функциональности. Затем вызовите этот экземпляр напрямую. Это может по-прежнему ощущаться как «отходы», поскольку один метод может напрямую называть другого, но ваше приложение будет гораздо более расширяемым и развязанным. –