люди подскажите. пишу класс для работы с БД. везде прочитал что в таких ситуациях лучше использовать интерфейс, а от него уже отнаследовать класс и в нем реализовать функции интерфейса.
Вопрос: для чего нужен интерфейс, если у меня будет всего один класс отнаследован от него и все функции я могу вынести просто в сам класс по работе с БД.
p.s. Если интерфейс здесь все таки не нужен то в каких практических задачах их используют?
23.08.07 13:28: Перенесено модератором из '.NET' — TK
Здравствуйте, busk, Вы писали:
B>люди подскажите. пишу класс для работы с БД. везде прочитал что в таких ситуациях лучше использовать интерфейс, а от него уже отнаследовать класс и в нем реализовать функции интерфейса. B>Вопрос: для чего нужен интерфейс, если у меня будет всего один класс отнаследован от него и все функции я могу вынести просто в сам класс по работе с БД. B>p.s. Если интерфейс здесь все таки не нужен то в каких практических задачах их используют?
В твоей задаче не нужно. Если у тебя есть требование в последующем цепляться к разным базам (MSSQL, Oracle и прочее). То тут можно уже завязываться на наследование или реализацию интерфейсов. Рекомедуют использовать реализацию интерфейсов — применять компонет можно, на зная деталей его внутренней релизации, так как этот компонет сконструирован в соотв. с заранее заданным набором операций, определенных в интерфейсе. Иными словами, это проще. ИМХО.
Здравствуйте, busk, Вы писали:
B>люди подскажите. пишу класс для работы с БД. везде прочитал что в таких ситуациях лучше использовать интерфейс, а от него уже отнаследовать класс и в нем реализовать функции интерфейса. B>Вопрос: для чего нужен интерфейс, если у меня будет всего один класс отнаследован от него и все функции я могу вынести просто в сам класс по работе с БД. B>p.s. Если интерфейс здесь все таки не нужен то в каких практических задачах их используют?
За интерфейс очень удобно спрятать логику, специфичную для конкретной базе.
К примеру у тебя есть один интерфейс IDbConnector, и несколько реализаций, для Oracle, MS SQL, MySQL и т.д.
При этом основная твоя бизнес логика, ядро твоей программы работает только с интерфейсом IDbConnector и ничего не знает о конкретной БД.
Нужную имплементацию можно выбирать на основе конфига при старте системы.
Здравствуйте, busk, Вы писали:
B>люди подскажите. пишу класс для работы с БД. везде прочитал что в таких ситуациях лучше использовать интерфейс, а от него уже отнаследовать класс и в нем реализовать функции интерфейса. B>Вопрос: для чего нужен интерфейс, если у меня будет всего один класс отнаследован от него и все функции я могу вынести просто в сам класс по работе с БД. B>p.s. Если интерфейс здесь все таки не нужен то в каких практических задачах их используют?
Самый весомый а может быть и единственный плюс от интерфейсов — с их помощью можно реализовать множественное наследования ... иначе их можно было бы и не использовать а обойтись только классами ....
Здравствуйте, torso, Вы писали:
T>Здравствуйте, busk, Вы писали:
B>>люди подскажите. пишу класс для работы с БД. везде прочитал что в таких ситуациях лучше использовать интерфейс, а от него уже отнаследовать класс и в нем реализовать функции интерфейса. B>>Вопрос: для чего нужен интерфейс, если у меня будет всего один класс отнаследован от него и все функции я могу вынести просто в сам класс по работе с БД. B>>p.s. Если интерфейс здесь все таки не нужен то в каких практических задачах их используют?
T>За интерфейс очень удобно спрятать логику, специфичную для конкретной базе. T>К примеру у тебя есть один интерфейс IDbConnector, и несколько реализаций, для Oracle, MS SQL, MySQL и т.д. T>При этом основная твоя бизнес логика, ядро твоей программы работает только с интерфейсом IDbConnector и ничего не знает о конкретной БД. T>Нужную имплементацию можно выбирать на основе конфига при старте системы.
А вот тут я тогда не догоняю немного. Раньше я думал что работаю из приложения с БД через класс. А вы пишите что "ядро программы работает только с интерфейсом" Можно тогда разъяснить, получается если б у меня был интерфейс и отнаследованный класс от него, то я бы просто мог вызывать методы интерфейса, а он бы юзал соответствующюю реализацию? У меня кажется идет небольшое изменение в мозгу Я прав (не про мозг ? Если да, то можно тогда немного развить по поводу наследования интерфейсов. Когда нужно множественное наследование интерфейсов?
...
B>А вот тут я тогда не догоняю немного. Раньше я думал что работаю из приложения с БД через класс. А вы пишите что "ядро программы работает только с интерфейсом" Можно тогда разъяснить, получается если б у меня был интерфейс и отнаследованный класс от него, то я бы просто мог вызывать методы интерфейса, а он бы юзал соответствующюю реализацию? У меня кажется идет небольшое изменение в мозгу Я прав (не про мозг ? Если да, то можно тогда немного развить по поводу наследования интерфейсов. Когда нужно множественное наследование интерфейсов?
Если у тебя класс наследуется от интерфейса, и не является абстрактным, то значит этот класс реализует этот интерфейс, т.е.
IDbConnector — интерфейс, его реализует класс OracleDbConnector.
В классе OracleDbConnector, расписана вся логика по работе с базой.
При этом у тебя есть другие классы, которые ничего не знают об OracleDbConnector, они знают, только об интерфейсе IDbConnector.
Вот возможный вариант использования.
// настраиваем работу с конкретной базой, в конфиге прописано, что нужно использовать OracleDbConnector
DbConnectorManager.Load("config.xml");
// получаем конкретный коннектор
IDbConnector conn = DbConnectorManager.Instance.GetConnector();
// работаем с базой через интерфейс...
conn.ExecuteQuery("...");
Насчет множественного наследования, к примеру ты хочешь чтобы твой класс можно было сравнивать и клонировать, для этого ты реализовываешь сразу 2 интерфейса IComparable, ICloneable.
P.S.: Но вполне возможно тебе это и не нужно совсем. Если у тебя всего лишь одна база, и не планируется использования чего другого, то ты можешь напрямую использовать OracleDbConnector и не парится.
начинаем писать большую систему, знаем что в перспективе будет юзаться БД.
но пока есть только интерфейс в архитектуре, реализаций нет.
наша группа пишет модуль, кот. использует БД через этот интерфейс
на этапе разработки, можно обойтись одними моками, но если мы хотим запустить весь модуль
мы можем не ждать пока другая группа заимплеменит этот класс + сама БД.
мы просто делаем свою реализацию, кот. просто сохраняет все в текстовом файле например
дешево и сердито, и все работает.
кстати этот тестовый класс и потом вполне может применятся.
Здравствуйте, busk, Вы писали: B>p.s. Если интерфейс здесь все таки не нужен то в каких практических задачах их используют?
Еще интерфейсы используются там, где ты хочешь работать с объектами, но не можешь или не хочешь отдавать код объекта целиком. В этом случае с объектом можно работать через интерфейс, передав (объявив) только его, например, при клиент-серверной организации кода через Remotig.
Все на самом деле очень просто. В ООП программе эта самая программа разбита (декомпозирована) на элементарные сущности, называемые классами. Как написано во всех учебниках классы обладают тремя особенностями — инкапсуляцией, наследованием и полиморфизмом. Для начала рассмотрим инкапсуляцию. Идея ее очень проста — запихиваем внутрь класса детали реализации, а наружу выставляем ... Некое формальное описание того, что снаружи с этим классом можно сделать. Это описание обысно называется контрактом (contract). В простейшем случае контракт это просто совокупность публичных методов, полей и свойств с их сигнатурой. Но поля, однако, обычно в контракт не включают, и вобще стараются избежать их использования.
Далее. Наследование. Здесь есть один важный момент, который в старых книжках по ООП мейнстриму обычно опускают. Дело в том, что бывают два вида наследования — наследование реализации и наследование контракта. Первое — по сути синтаксические сахар и призвано съэкономить на убирании дублирования кода в повторяющихся сущностей. А вот второе — фундаментальное понятие и неразрывно связано с полиморфизмом.
Полиморфизм нужен для того, чтобы написать один алгоритм, работающий с разными сущностями. В мейнстриме полиморфизм строится на наследовании контрактов. Т.е., при соблюдении LSP, алгоритм, умеющий работать с базовым контрактом, умеет работать и с любым классом, этот базовый контракт реализующим.
Теперь обратимся к .NET. В этом случае у нас есть ровно два способа реализовать базовый контракт — отнаследоваться от класса и реализовать интерфейс. В первом варианте у нас происходят сразу две вещи — наследуется реализация и контракт одновременно. Во втором — наследуется только контракт. В этом, собственно, и состоит принципиальное отличие полиморфизма с использованием интерфейсов и базовых классов.
На практике это означает буквально следующие — использование интерфейсов вместо базовых классов убирает побочные эффекты от базовой реализации. Как побочный эффект от гарантированного отсутствия наследования реализаций — множественное наследование не приводит к неприятным побочным эффектам. Еще один побочный эффект — при вынесении интерфейсов и классов-параметров в отдельную сборку эта сборка не несет реализации, а, следовательно, может быть использована в клиентском коде без зависимости от кода серверного.
Поэтому, по возможности, стоит избегать публичного наследования и вместо него использовать реализацию интерфейсов + агрегацию. Еще один важный принцип — если instance метод класса может быть вынесен за пределы класса, он должен быть вынесен за пределы класса.
+1, емко сказано.
Почти дословно с главой из GoF "Программирование в соответствие с интерфейсом, а не реализацией"; вначале показалось, сверил с книгой — действительно.
K>Самый весомый а может быть и единственный плюс от интерфейсов — с их помощью можно реализовать множественное наследования ... иначе их можно было бы и не использовать а обойтись только классами ....
Вы так аргументированно и умнО все объяснили... Наверное книшку прочитали?
Здравствуйте, torso, Вы писали:
T>Здравствуйте, busk, Вы писали:
T>...
B>>А вот тут я тогда не догоняю немного. Раньше я думал что работаю из приложения с БД через класс. А вы пишите что "ядро программы работает только с интерфейсом" Можно тогда разъяснить, получается если б у меня был интерфейс и отнаследованный класс от него, то я бы просто мог вызывать методы интерфейса, а он бы юзал соответствующюю реализацию? У меня кажется идет небольшое изменение в мозгу Я прав (не про мозг ? Если да, то можно тогда немного развить по поводу наследования интерфейсов. Когда нужно множественное наследование интерфейсов?
T>Если у тебя класс наследуется от интерфейса, и не является абстрактным, то значит этот класс реализует этот интерфейс, т.е. T>IDbConnector — интерфейс, его реализует класс OracleDbConnector. T>В классе OracleDbConnector, расписана вся логика по работе с базой. T>При этом у тебя есть другие классы, которые ничего не знают об OracleDbConnector, они знают, только об интерфейсе IDbConnector. T>Вот возможный вариант использования. T>
T>// настраиваем работу с конкретной базой, в конфиге прописано, что нужно использовать OracleDbConnector
T>DbConnectorManager.Load("config.xml");
T>// получаем конкретный коннектор
T>IDbConnector conn = DbConnectorManager.Instance.GetConnector();
T>// работаем с базой через интерфейс...
T>conn.ExecuteQuery("...");
T>
T>Насчет множественного наследования, к примеру ты хочешь чтобы твой класс можно было сравнивать и клонировать, для этого ты реализовываешь сразу 2 интерфейса IComparable, ICloneable.
T>P.S.: Но вполне возможно тебе это и не нужно совсем. Если у тебя всего лишь одна база, и не планируется использования чего другого, то ты можешь напрямую использовать OracleDbConnector и не парится.
// настраиваем работу с конкретной базой, в конфиге прописано, что нужно использовать OracleDbConnector
DbConnectorManager.Load("config.xml");
// получаем конкретный коннектор
IDbConnector conn = DbConnectorManager.Instance.GetConnector();
// работаем с базой через интерфейс...
conn.ExecuteQuery("...");
Неправильно поняли меня. Я имел ввиду что к примеру есть длл которая предоставляет интерфейс по работе с базой. Там понятно, юзаешь этот интерфейс и всё. А в вашем примере, какой смысл юзать интерфейс, если можно все тоже самое делать с объектом самого класса. И все равно для каждого класса (SqlDB, OracleDB etc) нужно будет писать свою реализацию Зачем тут интерфейс?
B>// настраиваем работу с конкретной базой, в конфиге прописано, что нужно использовать OracleDbConnector
B>DbConnectorManager.Load("config.xml");
B>// получаем конкретный коннектор
B>IDbConnector conn = DbConnectorManager.Instance.GetConnector();
B>// работаем с базой через интерфейс...
B>conn.ExecuteQuery("...");
B>
B>Неправильно поняли меня. Я имел ввиду что к примеру есть длл которая предоставляет интерфейс по работе с базой. Там понятно, юзаешь этот интерфейс и всё. А в вашем примере, какой смысл юзать интерфейс, если можно все тоже самое делать с объектом самого класса. И все равно для каждого класса (SqlDB, OracleDB etc) нужно будет писать свою реализацию Зачем тут интерфейс?
Мне кажется, что поняли правильно Для каждой базы нужно будет писать свою реализацию (интерфейса) — это да. Давай рассмотрим ситуацию, что ты решил работать с другой базой. Используя интерфейс (как показано в примере) ты можешь легко настроить свою программу для работы с другой базой (указав единожды другой класс, изменив одну строчку), без интерфейсов (в частности, а в общем — без наследования) пришлось бы все (!) вызовы старого класса изменять на вызовы нового или, как вариант, не создавать новый класс, а изменить старый, но тогда старый код будет потерян.
Never argue with a woman who reads. It's likely she can also think. (c)
Здравствуйте, Agent Smith, Вы писали:
AS>Здравствуйте, busk, Вы писали:
B>>
B>>// настраиваем работу с конкретной базой, в конфиге прописано, что нужно использовать OracleDbConnector
B>>DbConnectorManager.Load("config.xml");
B>>// получаем конкретный коннектор
B>>IDbConnector conn = DbConnectorManager.Instance.GetConnector();
B>>// работаем с базой через интерфейс...
B>>conn.ExecuteQuery("...");
B>>
B>>Неправильно поняли меня. Я имел ввиду что к примеру есть длл которая предоставляет интерфейс по работе с базой. Там понятно, юзаешь этот интерфейс и всё. А в вашем примере, какой смысл юзать интерфейс, если можно все тоже самое делать с объектом самого класса. И все равно для каждого класса (SqlDB, OracleDB etc) нужно будет писать свою реализацию Зачем тут интерфейс?
AS>Мне кажется, что поняли правильно Для каждой базы нужно будет писать свою реализацию (интерфейса) — это да. Давай рассмотрим ситуацию, что ты решил работать с другой базой. Используя интерфейс (как показано в примере) ты можешь легко настроить свою программу для работы с другой базой (указав единожды другой класс, изменив одну строчку), без интерфейсов (в частности, а в общем — без наследования) пришлось бы все (!) вызовы старого класса изменять на вызовы нового или, как вариант, не создавать новый класс, а изменить старый, но тогда старый код будет потерян.
Пример очень понятен, спасибо!
но только ради такого дела, как то даже неинтересно интерфейсы использовать
Здравствуйте, Владислав, Вы писали:
В>Здравствуйте, kisel, Вы писали:
K>>Самый весомый а может быть и единственный плюс от интерфейсов — с их помощью можно реализовать множественное наследования ... иначе их можно было бы и не использовать а обойтись только классами ....
В>Вы так аргументированно и умнО все объяснили... Наверное книшку прочитали?
Иронизируешь?
Высказал свою точку зрения, аргументировать и т.п. нет времени ... Можно пойти от противного ...
Приведите ситуацию, где обязательным является использование интерфейса, при условии что не реализуется множественное наследование ...
Я сходу не вижу такой ситуации ... Вот Вам и своего рода аргумент ...
Здравствуйте, kisel, Вы писали:
K>Здравствуйте, Владислав, Вы писали:
В>>Здравствуйте, kisel, Вы писали:
K>>>Самый весомый а может быть и единственный плюс от интерфейсов — с их помощью можно реализовать множественное наследования ... иначе их можно было бы и не использовать а обойтись только классами ....
В>>Вы так аргументированно и умнО все объяснили... Наверное книшку прочитали? K>Иронизируешь? K>Высказал свою точку зрения, аргументировать и т.п. нет времени ... Можно пойти от противного ... K>Приведите ситуацию, где обязательным является использование интерфейса, при условии что не реализуется множественное наследование ... K>Я сходу не вижу такой ситуации ... Вот Вам и своего рода аргумент ...
А я пока чай заварится смогу Вам кучу ситуаций набросать.
Три принципа OOD в основе своей подразумевают контракты (интерфейсы)
1) Gooogle -> 'Dependency Inversion Principle' -> обратите внимание на статью с обжектментор
2) AndrewVK c небольшой помощью Gamma et al. упоминал чуть раньше в этой нитке 'при соблюдении LSP, алгоритм, умеющий работать с базовым контрактом, умеет работать и с любым классом, этот базовый контракт реализующим' Чтоб надежно енфорсить LSP (Google -> Liskov Substitution) лучше скрывать все реализации контракта (интерфейса)
3) Open/Close Principle. Open часть предполагает публичный интерфейс
4) Google -> TDD Mock object
5) Чай готов...
Здравствуйте, kisel, Вы писали:
K>Здравствуйте, Владислав, Вы писали:
В>>Здравствуйте, kisel, Вы писали:
K>>>Самый весомый а может быть и единственный плюс от интерфейсов — с их помощью можно реализовать множественное наследования ... иначе их можно было бы и не использовать а обойтись только классами ....
В>>Вы так аргументированно и умнО все объяснили... Наверное книшку прочитали? K>Иронизируешь? K>Высказал свою точку зрения, аргументировать и т.п. нет времени ... Можно пойти от противного ... K>Приведите ситуацию, где обязательным является использование интерфейса, при условии что не реализуется множественное наследование ...
Тут много всего привели умного) Я спущусь на землю, банальный ремотинг. Без интерфейсов отделить сервер от клиента, не показывая клиенту весь код сервера — можно, но оооооочень геморно
Здравствуйте, busk, Вы писали:
B>люди подскажите. пишу класс для работы с БД. везде прочитал что в таких ситуациях лучше использовать интерфейс, а от него уже отнаследовать класс и в нем реализовать функции интерфейса. B>Вопрос: для чего нужен интерфейс, если у меня будет всего один класс отнаследован от него и все функции я могу вынести просто в сам класс по работе с БД. B>p.s. Если интерфейс здесь все таки не нужен то в каких практических задачах их используют?
Сам и ответил на свой вопрос — не нужен тебе интерфейс. Понадобится реализовать возможность подключения к различным БД — опишешь интерфейс, заменишь в объявлении переменной имя класса на имя интерфейса. Не усложняй себе жизнь раньше времени.
Здравствуйте, Ivan Danilov, Вы писали:
ID>Здравствуйте, kisel, Вы писали:
K>>Здравствуйте, Владислав, Вы писали:
В>>>Здравствуйте, kisel, Вы писали:
K>>>>Самый весомый а может быть и единственный плюс от интерфейсов — с их помощью можно реализовать множественное наследования ... иначе их можно было бы и не использовать а обойтись только классами ....
В>>>Вы так аргументированно и умнО все объяснили... Наверное книшку прочитали? K>>Иронизируешь? K>>Высказал свою точку зрения, аргументировать и т.п. нет времени ... Можно пойти от противного ... K>>Приведите ситуацию, где обязательным является использование интерфейса, при условии что не реализуется множественное наследование ... ID>Тут много всего привели умного) Я спущусь на землю, банальный ремотинг. Без интерфейсов отделить сервер от клиента, не показывая клиенту весь код сервера — можно, но оооооочень геморно
Почему же ... абстрактынй класс не подойдёт?
Не убедительно ...
По моему все очевидно , если некий класс реализовывает интерфейс, тогда этот класс АВТОМАТИЧЕСКИ реализует множественное наследование ... так как он наследуется от 2-х сущностей, от базового класса наследует конкракт + реализацию а от интерфейса наследует только контракт ...
А сам интерфейс, без реализации никому не нужен ... вот и получается если используется интерфейс, тогда реализовывается множественное наследование ...
Здравствуйте, rsn81, Вы писали:
R>Почти дословно с главой из GoF "Программирование в соответствие с интерфейсом, а не реализацией"; вначале показалось, сверил с книгой — действительно.
Читал GoF последний раз лет 5 назад, так что все совпадения случайны
Здравствуйте, busk, Вы писали:
B>люди подскажите. пишу класс для работы с БД. везде прочитал что в таких ситуациях лучше использовать интерфейс, а от него уже отнаследовать класс и в нем реализовать функции интерфейса. B>Вопрос: для чего нужен интерфейс, если у меня будет всего один класс отнаследован от него и все функции я могу вынести просто в сам класс по работе с БД. B>p.s. Если интерфейс здесь все таки не нужен то в каких практических задачах их используют?
"Чистое" ООП предполагает, что есть некоторая среда, в которой существуют объекты и эти объекты обмениваются между собой сообщениеями. По сути, оно так и есть в динамических ООЯ (или, как их называют в народе, прототип-ориентированных языках). Конечно, такой подход очень гибок, даже слишком гибок и часто эта гибкость нужна как собаке пятая нога. А, между тем, он обладает рядом недостатков. В частности, программы на прототип-ориентированных языках тяжелее отлаживать: можно банально ошибиться в названии сообщения при наборе текста и эта ошибка выявится только тогда, когда это сообщение реально будет послано в рантайме. А почему бы нам не заставить компьютер следить за правильностью программы? В таком виде это сделать невозможно, но можно для компьютера в программе оставить предписания, какой объект какие сообщения может обрабатывать, чтобы нас ударил по рукам компилятор. Такой подход вводит некоторые ограничения, но это не смертельно, к тому же многие ограничения (если это действительно необходимо!) обходятсяс помощью всяких RTTI и Reflection.
Собственно, интерфейс и является этим самым предписанием для компилятора. Но это пока ничего не говорит, потому нужно некая связка с тем, что и так хорошо известно программистам на C++/Java/C#. А им, как раз, хорошо известны классы. Так вот, на самом деле, классы в таких языках являются не классами, а паттернами для одновременного описания интерфейса, и класса, этот интерфейс реализующего! Все public-члены класса являются членами некоторого "анонимного" интерфейса, причём для них тут же даётся доп. реализация. Это, своего рода синтаксический сахар (на самом деле, в отстутсвии extenstion-методов это не совсем так). По идее, можно вообще обойтись без наследования классов, а ограничиться только наследованием интерфейсов и реализацией интерфейсов в классах.
Интерфейс нужен для того, чтобы от объекта можно было ожидать определённого поведения. Например, розетка ожидает от объекта, что он потребляет перменный ток 220 вольт, с частотой 50Гц, и что у объекта есть два штырька определённых размеров. Потому, любой объект, потребляющий электричество таким способом, должен реализовывать интерфейс IВилка. Розетку при этом вобще не интересует, что и как делает прибор, ей важен только один аспект функционирования прибора — потребление питания. Другой пример: человек ожидает от объекта, что он покажет ему фильм. Потому, любой объект, показывающий фильм, должен реализовывать интерфейс IПоказывательФильмов. Человека не интересует, например, как работает прибор, или каким образом он питается (от розетки, аккумуляторов). Телевизор реализует интерфейсы из обоих примеров, портативный DVD-плеер — только второй.
Кто-то не согласится со мной, ткнёт меня в "непреложную истину" про то, что ООП = инкапсуляция + наследование + полиморфизм, а всякие Self и JS — это приходящее. Но, во-первых, не помешало бы для полноты картины не помешало бы знать оба подхода, а во-вторых, ИМХО, подход прототипо-ориентированных языков более интуитивен. Кроме того, как мне кажется, каноническое определение ООП больше относится к технической стороне ООЯ, а вот мыслить человеку в подобных категориях не всегда целесообразно.