Завязался тут у нас спор с коллегой по поводу "философии программирования". Интересно какие еще мнения будут относительно плюсов и минусов?
Не для каких либо частных случаев, а именно как основной подход.
Итак — Вариант 1 (для каждого класса необходимо иметь не менее 1 интрефейса. Получаем полный контроль над видимостью)
public interface IAbc
{
// пустой
}
public interface IAbcd:IAbc
{
//часто всего один метод, что бы потом из интерфейсов можно было конструировать различные объектыvoid Method1();
}
.....
internal class Abc:IAbc
{
public void F1() {...}
public void Fn() {...}
}
internal class Abcd:Abc,IAbcd
{
public void Method1() {...}
public void Fx1() {...}
public void Fxn() {...}
}
.....
void Xxxx()
{
// доступ и работа только через интерфейсы, напрямую к объектами запрещено обращаться
IAbcd t1 = new Abcd();
t1.Method1(); // можно
t1.F1(); // нельзя
}
Вариант 2 (интерфейсы только когда действительно необходимо, нефиг плодить лишнее)
internal class Abc
{
protected void F1() {...}
protected void Fn() {...}
// можно было и в интерфейс выкинуть, если бы была необходимость обязательной имплементацииpublic virtual Method1() {}
}
internal class Abcd:Abc
{
public override void Method1() {...}
protected void Fx1() {...}
protected void Fxn() {...}
}
void Xxxx()
{
Abcd t1 = new Abcd();
t1.Method1(); // можно
t1.F1(); // нельзя
}
Возможно информации маловато, но пока не хочу перегружать подробностями. Надеюсь различия подходов понятны.
Здравствуйте, AlexNek, Вы писали:
AN>Итак — Вариант 1 (для каждого класса необходимо иметь не менее 1 интрефейса
Нафига?
AN>Получаем полный контроль над видимостью)
Какая то ерунда.
AN>Возможно информации маловато, но пока не хочу перегружать подробностями. Надеюсь различия подходов понятны.
Ответ на исходный вопрос простой и сложный одновременно. Интерфейсы в 99% случаев применяют там, где необходимо изолировать публичные контракты какой то подсистемы. Собственно, все.
... << RSDN@Home 1.2.0 alpha 5 rev. 1537 on Windows 7 6.1.7601.65536>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, AlexNek, Вы писали:
AN>>Итак — Вариант 1 (для каждого класса необходимо иметь не менее 1 интрефейса
AVK>Нафига?
Ну концепт у человека такой. Пищит так как будто только что из Таиланда приехал
"Какой изумительный концепт". И я никак не могу врубится почему.
AN>>Получаем полный контроль над видимостью)
AVK>Какая то ерунда.
Ну не совсем полная, мне приводился где-то следующий пример (просто как принцип, а не как пример рабочего кода):
interface IText
{
public string Text { get; set; }
}
class LabelEx:Label,IText
{
}
...
Control ctl = new LabelEx();
// имеем возможность пользоваться как обычным контролом "внутри пакета"
ctl.BackgroundColor = Color.Blue;
form.Add(ctl);
...
// наружу выдается только возможность прочитать/установить текст
IText label = GetControl;
label.Text = "Sample";
Небольшие изменения и получаем универсальный "конструктор" нужных объектов "наружу".
interface IAllowed:IText,IBitmap
{
}
class LabelEx:Label,IAllowed
{
...
}
Я просто пока не могу сформулировать затыки такого подхода, хотя ж..ой чувствую что то должно быть.
Здравствуйте, AlexNek, Вы писали:
AVK>>Нафига? AN>Ну концепт у человека такой.
Ну, альтернативно одаренных программистов в природе встречается достаточно, чтобы очередной сильно удивлял.
AN>Ну не совсем полная, мне приводился где-то следующий пример (просто как принцип, а не как пример рабочего кода):
Ну и? Ради такой ерунды плодить кучу интерфейсов? По мне так стандартный internal вполне себе покрывает основные потребности.
Интерфейсы нужны, когда ты хочешь явно задекларировать какие то контракты для внешнего кода. Вот там они незаменимы.
AN>Я просто пока не могу сформулировать затыки такого подхода, хотя ж..ой чувствую что то должно быть.
Да затык то очень простой — куча тупой работы программиста ради крайне незначительного бенефита.
... << RSDN@Home 1.2.0 alpha 5 rev. 1537 on Windows 7 6.1.7601.65536>>
Здравствуйте, AlexNek, Вы писали:
AN>Завязался тут у нас спор с коллегой по поводу "философии программирования". Интересно какие еще мнения будут относительно плюсов и минусов? AN>Не для каких либо частных случаев, а именно как основной подход.
AN>void Xxxx() AN>{ AN> // доступ и работа только через интерфейсы, напрямую к объектами запрещено обращаться AN> IAbcd t1 = new Abcd(); AN> t1.Method1(); // можно AN> t1.F1(); // нельзя AN>}
"void Xxxx()" не должен сам создавать объекты, иначе теряется весь смысл
Здравствуйте, AlexNek, Вы писали:
AN>Возможно информации маловато, но пока не хочу перегружать подробностями. Надеюсь различия подходов понятны.
Представьте, что вы директор театра и нанимаете на работу актера Пожарова. Будете ли вы в трудовом договоре с Ивановым писать, что именно он должен делать и говорить на сцене? Наверное, нет. Во-первых, сегодня у вас Пожаров, а завтра Иванов. Если договор с Пожаровым потеряется, как с Ивановым договариваться? Во-вторых, партнерша Пожарова по спектаклю актриса... мнэ... Петрова должна знать, что Пожаров будет делать и говорить, как ей иначе репетировать? А дать ей почитать договор с Пожаровым нельзя — там последним пунктом указана огромная зарплата Пожарова, чего Петрова не потерпит. В-третьих, зачем Пожарова заставлять читать набор реплик вплоть до "Домком — око недреманное", если роль Аллилуи известна всякому приличному театралу? Подумав, вы пишете в договоре: "...Пожаров принимается на следующие роли: Аллилуи, Лоханкина...".
Далее, вам надо принять на работу бабу Дусю, уборщицу. Ее обязанности не настолько жестко закреплены, чтобы каждое слово регламентировалось. К тому же, она, в отличие от предшественницы бабы Нюры, просит назначить ее убирать поздно по вечерам, а не рано утром. Следовательно, вы можете прямо в ее договоре написать: "вытирать пыль с одиннадцати до двенадцати ежевечерне". Эти детали никого не интересуют: ни Пожарова, ни Иванова, ни Петрову. Они к этому времени уже покидают театр. Будете ли вы писать роль уборщицы, вводить ее в спектакли и принимать бабу Дусю с указанием этой роли? Я — нет. Хотя еще и не такие режиссеры бывают. Особенно, когда первый раз прочитают про Сценические Паттерны ("...паттерн Вешалка был придуман еще Станиславским...").
AVK>Ну и? Ради такой ерунды плодить кучу интерфейсов? По мне так стандартный internal вполне себе покрывает основные потребности. AVK>Интерфейсы нужны, когда ты хочешь явно задекларировать какие то контракты для внешнего кода. Вот там они незаменимы.
а почему бы не задекларировать контракты для внутреннего кода?
с точки зрения конкретного класса, все остальные — "внешние" по отношению к нему
конечно если класс всегда и только всегда будет жить внутри своего модуля (сборки), то в этом действительно смысла нет
но если есть шанс что кто-то захочет реюзнуть класс, скопировав его в другой проект, и не хочет тянуть всю сборку?
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, AlexNek, Вы писали:
AN>>Я просто пока не могу сформулировать затыки такого подхода, хотя ж..ой чувствую что то должно быть.
AVK>Да затык то очень простой — куча тупой работы программиста ради крайне незначительного бенефита.
Это парируется, зато хорошая ххх (вместо ххх могут подставлятся различные умные слова)
Нужны "технические" затыки. Пожалуй, попрошу у него пример для поиграться и попробую примерчик не нагло "убить".
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, AlexNek, Вы писали:
AN>>Завязался тут у нас спор с коллегой по поводу "философии программирования". Интересно какие еще мнения будут относительно плюсов и минусов? AN>>Не для каких либо частных случаев, а именно как основной подход.
AN>>void Xxxx() AN>>{ AN>> // доступ и работа только через интерфейсы, напрямую к объектами запрещено обращаться AN>> IAbcd t1 = new Abcd(); AN>> t1.Method1(); // можно AN>> t1.F1(); // нельзя AN>>}
A>"void Xxxx()" не должен сам создавать объекты, иначе теряется весь смысл
Да не хотелось много текста писать, надо было строчки разделить многоточием.
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, AndrewVK, Вы писали:
AVK>>Ну и? Ради такой ерунды плодить кучу интерфейсов? По мне так стандартный internal вполне себе покрывает основные потребности. AVK>>Интерфейсы нужны, когда ты хочешь явно задекларировать какие то контракты для внешнего кода. Вот там они незаменимы.
A>а почему бы не задекларировать контракты для внутреннего кода? A>с точки зрения конкретного класса, все остальные — "внешние" по отношению к нему
A>конечно если класс всегда и только всегда будет жить внутри своего модуля (сборки), то в этом действительно смысла нет A>но если есть шанс что кто-то захочет реюзнуть класс, скопировав его в другой проект, и не хочет тянуть всю сборку?
Копировать не собираются, просто хотят иметь ящик внутри которого можно делать все, а снаружи только то, что позволено, причем объекты и снаружи и внутри хочется иметь одинаковые.
Здравствуйте, Abyx, Вы писали:
A>а почему бы не задекларировать контракты для внутреннего кода?
Зачем?
A>с точки зрения конкретного класса, все остальные — "внешние" по отношению к нему
С точки зрения класса — вполне возможно. Но я говорил про точку зрения дизайна программы или модуля программы в целом.
A>но если есть шанс что кто-то захочет реюзнуть класс, скопировав его в другой проект, и не хочет тянуть всю сборку?
Зависит от назначения этого класса. Если это просто набор хелперов, то смысла выносить контракты наружу никакого. А вот явно введенные слои абстракции — их контракты надо описывать интерфейсами практически всегда.
... << RSDN@Home 1.2.0 alpha 5 rev. 1537 on Windows 7 6.1.7601.65536>>
Здравствуйте, AlexNek, Вы писали:
AN>Это парируется, зато хорошая ххх (вместо ххх могут подставлятся различные умные слова)
Веру техническими аргументами не оспоришь.
AN>Нужны "технические" затыки.
Это вполне технический. Ну если хочешь — технологический затык. Потому что синтаксический мусор не только усложняет первоначальное написание, но и засоряет код при чтении ненужными сущностями.
Но если тебя таки интересуют чисто технические проблемы — есть несколько.
1) Вызов интерфейса в большинстве практических случаев — двойная косвенность. Т.е. вызов накладнее даже виртуального вызова, не говоря уж про раннесвязанный.
2) Особенность реализации interface table (аналог vmt для интерфейсов) в рантайме такова, что каждый загруженный в память интерфейс увеличивает потребную для загрузки всех последующих классов память (ЕМНИП на 4/8 байт в зависимости от разрядности). При большом количестве интерфейсов это обеспечивает вполне заметный оверхед по памяти. На это накладывается оверхед по хранению метаданных самих интерфейсов.
3) Создание делегата на метод интерфейса в некоторых ситуациях приводит к сильному замедлению этого конструирования.
... << RSDN@Home 1.2.0 alpha 5 rev. 1537 on Windows 7 6.1.7601.65536>>
(Все случае когда интерфейс напрашивается сам собой — опускаем).
Если вы делаете один единственный класс с уникальной функциональностью — то этот класс уже имеет свой публичный интерфейс — незачем городить лишнюю абстракцию, которую вдобавок ещё и нужно поддерживать.
Если вы делаете классы, которые имплементят какие-то уже известные интерфейсы — не ленитесь создавать интерфейсы, заодно с отсылками к первоисточниками.
Пример: это наличие хорошо задокументированных интерфейсов из W3C DOM (XML): Element, Node, Attribute и т.п. Весь вэб на них держится. И всё идеально укладывается в дотнетные интерфейсы. Что в реальности? System.Xml это набор классов "в себе" — подменить имплементацию невозможно, хотя это заложено изначально, там на правах internal даже есть DOMImplementation (нафига тока оно надо, если оно internal и не выполняет своих функций?). Правда в этом случае в большей степени — это перманентная проблема MS — всё время переизобретать колесо и погоня за призраками.
В этом же смысле XLinq — обратная сторона медали — в тыщу раз лучше, а код внутри — просто прелесть. Перестали копировать W3C DOM, — на все случаи не годиться, но покрывает 99% потребностей. А те, что не покрывает, например потребность быстрой навигации назад (previous sibling и т.п.) — благодаря annotations — решаема. В этом случае следовать интерфейсам — было бы вредно.
Здравствуйте, AndrewVK, Вы писали:
AVK>Интерфейсы в 99% случаев применяют там, где необходимо изолировать публичные контракты какой то подсистемы.
И в 98% случаев для обеспечения ООП-шного полиморфизма.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, AlexNek, Вы писали:
AN>>Это парируется, зато хорошая ххх (вместо ххх могут подставлятся различные умные слова)
AVK>Веру техническими аргументами не оспоришь.
Я уже и не знаю какие аргументы использовать.
Просто боюсь подумать, что туда кому то другому может прийдется что то добавлять. Он еще туда MVP паттерн запиндрючил, получилось не менее 30 классов и интерфейсов без учета различных элементов отображения.
А основные классы создает через активатор по динамически создаваемым именам. Блин, и книги отобрать низзя
Здравствуйте, AlexNek, Вы писали:
AN>Просто боюсь подумать, что туда кому то другому может прийдется что то добавлять. Он еще туда MVP паттерн запиндрючил, получилось не менее 30 классов и интерфейсов без учета различных элементов отображения. AN>А основные классы создает через активатор по динамически создаваемым именам. Блин, и книги отобрать низзя
У меня есть проект в котором используется куча интерфейсов. Достался в наследство.
Интерфейсы эти: для DataAccess, для BussinessRules, для фасадов. Проблема только в том, что ничего кроме головной боли они не добавляют, потому что, вместо того что бы написать новый метод в одном (трёх) местах — приходится рыскать и добавлять ещё и во всех интерфейсах (т.е. вместо трёх — шесть). При чём, как бы оно там ни было правильно — но реально, никаких DI или тестов — нет. Т.е. это живёт само в себе. Такое нужно давить, интерфейса на фасаде хватило бы. Интерфейс проще добавить, если он реально необходим, тем более в шарпе, с его способносятм к рефакторингу.
Здравствуйте, AlexNek, Вы писали:
AN>Завязался тут у нас спор с коллегой по поводу "философии программирования". Интересно какие еще мнения будут относительно плюсов и минусов? AN>Не для каких либо частных случаев, а именно как основной подход.
В качестве основного подхода можно порекомендовать задавать себе почаще вопрос при принятии подобных решений — а какую конкретную проблему мы решаем. Если не конкретно, а сильно в общем, то интерфейсы и большинство паттернов, на них базирующиеся, позволяют рещать проблемы так или иначе связанные с гибкостью кода. Но как нам известно из закона сохранения сложности за всё нужно платить. Плата за интерфейсы — количественное усложнение кода и увеличение, порой весьма существенное, сложности восприятия кода. Тотальное использование интерфейсов скорее всего приведёт к тотальной потери восприятия кода, что в более менее сложном проекте неизбежно закончится полной или частичной потерей контроля над кодом. Там где на поиск и решение проблемы потребовалось бы пару минут будет уходить по нескольку часов, а там где нужно было бы несколько часов или дней, придётся тратить недели и месяцы.
В простонародье подобные решения называются overdesign/overarchitecture, когда фактическая получаемая выгода от принятых решений низка или полностью отсутсвует, а привнесённые существенные усложнения тупо не замечаются или старательно игнорируются. Но, к сожалению, сложность очень коварна. Если бы мы имели дело с одним, пусть даже большим, монолитным куском некой субстанции, то можно было бы напрячься и одним махом разрешить все проблемы, которые от неё исходят. Но сложность не монолит, а скорее куча мелкой крошки и песка, и с каждой крошкой и песчинкой приходтся иметь дело индивидуально. Лучше не нести весь этот мусор в код с самого начала. Голова она хоть и большая, но у программиста ей и без этого есть о чём болеть.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, SV., Вы писали:
SV.>Представьте, что вы директор театра и нанимаете на работу актера Пожарова. Будете ли вы в трудовом договоре с Ивановым писать, что именно он должен делать и говорить на сцене? ...
Довольно абстрактно сказано, примерно так же, как и в случае с большим количеством ненужных интерфейсов.
AndrewVK всё верно говорил: всё должно согласовываться с принципом достаточности, необходимости и разумности и только. В каждом конкретном случае надо думать, просто думать... А не бездумно применять наугад тот или иной паттерн. Если речь идёт об интерфейсах — это всего лишь контракты для сокрытия реализации... а реализацию нужно скрывать только там, где это крайне необходимо, например: плагины, компоненты, модули, семейства сущностей, имеющих общие черты (фигуры, например)... Вот и всё. Ничего лишнего...
Здравствуйте, AlexNek, Вы писали:
AN>Завязался тут у нас спор с коллегой по поводу "философии программирования". Интересно какие еще мнения будут относительно плюсов и минусов? AN>Не для каких либо частных случаев, а именно как основной подход.
Оказалось даже еще хуже чем предполагал