2010-02-05 3 views
4

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

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

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

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

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

Заранее спасибо, Carl J.

ответ

1

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

  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

Итак, если я говорю, что тип возвращаемого метода - это PropertyBase (абстрактный класс), я могу затем вернуть либо Живой, либо Коммерческий объект? Я думал, что для того, чтобы метод мог возвращать разные типы, каждый тип должен был реализовать интерфейс. –

+0

yep, см. Мой пример, который я добавил – Mark

+0

Да, вы можете вернуть базовый класс и рассматривать как Residental, так и Commercial как общий набор базовых объектов. Это то, что известно в языке ООП как LSP, или в принципе Liskov Substitution, и в основном это означает, что если вы наследуете что-то, тогда его можно рассматривать как как конкретный подкласс, так и (возможно, абстрактный) базовый класс. Наследование - это «IS A». A ResidentialProperty * IS A * PropertyBase. Коммерческая недвижимость * IS A * PropertyBase. –

1

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

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

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

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

+0

Спасибо Адаму. Как жилые, так и коммерческие классы имеют общие атрибуты (Id, Title, Description, Address), однако каждый из них имеет свои собственные атрибуты.У жилых было бы NumberOfBedroom и NumberOfBathrooms, в то время как у Commercial были бы другие, которых у Жилища нет. –

+0

Я не уверен, что вы намереваетесь, чтобы это была сложная система или нет, если это так, я бы не исключил никакого атрибута для любого заданного типа свойства. Конечно, коммерческая недвижимость может иметь спальни и ванные комнаты, а жилая недвижимость может иметь офисные помещения. Вы можете, insteand, рассмотреть объект унифицированного свойства, который имеет настраиваемый набор атрибутов, который может быть применен однозначно к каждому свойству, возможно, предоставляя общие шаблоны свойств, используемых для жилых и comemrcial свойств, но не требующих их. –

1

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

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

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

Рано или поздно вы попадаете в ситуацию, когда вам нужно многократное наследование, и вы ввернуты.

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

+1

В книге «Руководства по разработке рамок» есть некоторая большая информация о том, когда использовать интерфейсы и когда использовать абстрактные классы. – si618

+0

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

0

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

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

0

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

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

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

+0

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

3

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

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

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

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

Смежные вопросы