Что я должен использовать, интерфейс, абстрактный класс или оба? - PullRequest
4 голосов
/ 06 февраля 2010

Итак, гипотетически, я создаю какое-то приложение для недвижимости на C #. Для каждого типа свойств я собираюсь создать класс, такой как ResidentialProperty и CommercialProperty. Эти два класса, а также все другие классы свойств будут иметь некоторые общие свойства, такие как Id, Title, Description и Address information.

То, что я хотел бы сделать, это:
а) вернуть коллекцию объектов, которые содержат только основную информацию
b) иметь возможность либо вызвать метод, такой как GetProperty (id), который создаст и возвратит либо ResidentialProperty, либо CommercialProperty, либо вызвать GetProperties (), который возвратит коллекцию того или другого, либо обоих.

Таким образом, с учетом вышесказанного, возможно, имеет смысл создать абстрактный класс с именем BasicProperty (или PropertyBase), который содержит все общие атрибуты и имеет расширение ResidentialProperty и CommercialProperty из него. Это решило бы проблему # 1, так как я мог бы создать метод, который возвращает коллекцию BasicProperties.

Но для # 2, чтобы иметь возможность возвращать либо один тип свойства, либо другой, мне понадобился бы интерфейс (IProperty), и у меня должны были бы наследоваться классы Residential и Commercial, а затем GetProperty (id) и GetProperties () вернуть объект IProperty (или, поскольку они наследуются от IProperty, можно ли вернуть их как есть, а не как интерфейс?)?

Теперь, если мне нужно использовать интерфейс, что мне делать с классом BasicProperty?
- Я оставляю это как реферат и реализую интерфейс? Или
Я оставляю это как резюме, и все 3 класса реализуют Интерфейс? Или
- Разве я не создаю его как абстрактный, не помещаю всю основную информацию в Интерфейс, а BasicProperty, ResidentialProperty и CommercialProperty реализуют Интерфейс?

Спасибо заранее, Карл Дж.

Ответы [ 6 ]

3 голосов
/ 06 февраля 2010

Хотя я чувствую, что определение интерфейса для начала почти всегда хорошая идея, просто потому, что это помогает вашему коду быть гибким в будущем, похоже, что в этом случае вы на самом деле не нужно , чтобы сделать это. Ваши методы GetProperty и GetProperties могут использовать ваш абстрактный базовый класс в качестве возвращаемого значения.

Думайте об этом так: что если бы у меня был метод с именем GetShape? Предположительно он вернул бы Shape, верно? Допустим, Shape является абстрактным базовым классом, а некоторые производные классы Triangle, Square, Circle и т. Д.

Но треугольник - это форма, квадрат - это форма и т. Д. - каждый из них оказывается больше просто формы Но, тем не менее, они являются формами . Поэтому, если я скажу «дайте мне форму» и вы дадите мне квадрат, вы делаете то, что я просил. Никакого смешного дела нет.

Это один из основных принципов ООП: экземпляр производного класса является экземпляром его базового класса; это также больше , чем это.

1 голос
/ 06 февраля 2010

По моему мнению, вам следует избегать использования абстрактных классов, если это не имеет абсолютно никакого смысла.

Много общего поведения может быть передано вашим сущностям посредством агрегации с использованием компонентов, и вы можете опубликовать это поведение с помощью интерфейсов.

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

Рано или поздно вы сталкиваетесь с ситуацией, в которой вы действительно хотите множественное наследование, и вы облажались.

Не то чтобы я был хардлайнером в этом, потому что большая часть нашей кодовой базы действительно использует базовые абстрактные классы для вышеупомянутого, но они реализуют интерфейсы и весь код, принимаемый в этих классах, говорит их через интерфейсы, так что мы можем переключить базовые классы на что-то более гибкое, если потребуется.

1 голос
/ 06 февраля 2010

Абстрактный класс используется для обеспечения общего поведения. Интерфейс используется для предоставления определенного набора методов и свойств независимо от их поведения.

Если ваши ResidentialProperty и CommercialProperty обеспечивают некоторое общее поведение, то, вероятно, имеет смысл реализовать это поведение в абстрактном классе, и каждый из них наследует от этого класса. Предположительно, они также будут иметь некоторое пользовательское поведение, в противном случае нет необходимости в подклассе, тогда будет достаточно просто иметь свойство PropertyType, чтобы описать, какой тип свойства является экземпляром.

Затем вы можете предоставить столько интерфейсов, сколько считаете нужным, IPropertyBase, IResidentialProperty и / или ICommercialProperty. Это действительно зависит от того, ожидаете ли вы, что эта библиотека будет использоваться как база для других реализаций, которые могут иметь тот же интерфейс, что и один или несколько ваших классов, но не то же поведение, что и ваш базовый абстрактный класс. Другим преимуществом предоставления интерфейсов, представляющих ваши типы, является более легкое использование для модульного тестирования.

На самом деле невозможно ответить на этот вопрос абсолютно, потому что это действительно зависит от того, как ваши объекты, вероятно, будут использоваться, но я надеюсь, что этот ответ даст вам полезное руководство.

1 голос
/ 06 февраля 2010

Из того, что я могу собрать, вы говорите здесь о двух разных вещах.

  1. Классовая структура
  2. Доступ к данным этих классов

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

Но я не понимаю, почему вы не можете создать класс доступа к данным с методом GetProperty(id), который задает тип возврата PropertyBase

т.е.

public PropertyBase GetProperty(long id)

в реализации GetProperty вы можете сконструировать ResidentialProperty или CommercialProperty (в зависимости от того, какую логику бизнеса / базы данных вы хотите) и затем вернуть, c # позволяет вам это сделать.

Может, я вас не понял?

НТН

EDIT ::

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    class DataAccessLayer
    {
        public PropertyBase GetSomething(int id)
        {
            if (id > 10)
                return new CommercialProperty();
            else
                return new ResidentialProperty();
        }

    }

    class PropertyBase { }
    class ResidentialProperty : PropertyBase { } 
    class CommercialProperty : PropertyBase { }
}
0 голосов
/ 06 февраля 2010

Не называйте ваш базовый класс или интерфейс BasicProperty или PropertyBase, просто назовите его Property. У вас не будет и Property, и BasicProperty? Вы будете действовать с классами свойств или интерфейсами.

Абстрактный класс - это почти то же самое, что интерфейс с тем отличием, что абстрактный класс может хранить состояние в переменных поля. Когда ваши Свойства имеют данные, такие как адрес, который хранится, абстрактный класс с полем является одним из способов сделать это.

Теперь подклассы класса являются одним из примеров книжек с картинками OOD, но есть и другие способы различения объектов, кроме этого, посмотрите на декоратор и шаблоны поведения. Вы должны создавать подклассы только в том случае, если вам нужно переопределить методы базового класса. Взгляните на это например.

0 голосов
/ 06 февраля 2010

Быстро не о разнице, как я ее вижу. Вы всегда можете использовать абстрактный базовый класс, даже когда вы реализуете интерфейсы. Интерфейсы не помогают вам избежать дублирования кода, которое вам следует (см. Принцип DRY ), но это не заставляет вас делать что-то особенное, что облегчает их объединение с другими базовыми классами или интерфейсами.

С другой стороны, абстрактный базовый класс может удалить некоторое дублирование, и некоторые вещи в базе легче изменить, не затрагивая производные классы. Последнее очень хорошо, когда вы реализуете библиотеку классов, которую используют другие. Если вы изменяете вещи в интерфейсах в библиотеке, все реализации этого интерфейса должны измениться! Это может быть очень маленькой проблемой, если вы реализуете приложение только с небольшой группой разработчиков. Но, как уже говорили другие, базовый класс заставляет вас извлекать из него пользу, и тогда вы не сможете извлечь из чего-то еще, если возникнет такая необходимость.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...