Как я могу предотвратить дырявую абстракцию?

Я пишу оболочку Active Directory, пытаясь следовать SOLID и другим передовым методам. Интерфейс в настоящее время "IActiveDirectory".

Проблема, с которой я столкнулся сейчас, заключается в том, что реализация ActiveDirectory должна реализовать IDisposable, чтобы избавиться от нескольких ресурсов, которые создаются и удаляются внутри этой оболочки, и я не уверен, как решить эту проблему при попытке закодировать интерфейс и т. д. Я не хочу создавать дырявую абстракцию (т. е. украшать IActiveDirectory с помощью IDisposable.) Я не могу сделать службу гранулярной (т. е. ограничивать создание/удаление ресурсов вызовами методов) из-за производительности базовых зависимостей.

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

Как я могу предоставить потребителям контракт (то есть интерфейс) без утечки абстракции оболочки ресурса? Должен ли я просто выставить реализацию без интерфейса? Есть ли способ для моего потребителя или контейнера внедрения зависимостей управлять сроком службы этой службы?


person Martin Bliss    schedule 01.11.2013    source источник
comment
Мне нужен чистый и удобный способ, с помощью которого потребитель мог бы сигнализировать об окончании работы с ресурсом. -- это именно то, что IDisposable есть. Вы не можете абстрагироваться от всего.   -  person    schedule 01.11.2013
comment
Да, я знаю, что это именно то, что такое IDisposable, и у меня нет проблем с тем, чтобы поместить его в конкретный класс. Однако мне не нравится помещать его в интерфейс, потому что я создаю дырявую абстракцию, в соответствии с которой я предполагаю, что всем реализациям требуется вызов метода Dispose, что нарушает Лисков. Как вы думаете, было бы лучше просто выставить бетон без интерфейса?   -  person Martin Bliss    schedule 02.11.2013
comment
Совершенно верно, в соответствии с LSP и другими критериями, что Dispose ничего не делает. Размещение его на интерфейсе не означает, что все реализации нуждаются в удалении (любая реализация, которая не может просто добавить void Dispose() {}), это означает, что некоторые реализации нуждаются в удалении (что верно).   -  person    schedule 02.11.2013
comment
@delnan Я все еще считаю, что это нарушение Лискова именно потому, что интерфейс подчиняется потребностям по крайней мере одного из его конкретных элементов, и что возможно, что по крайней мере одна реализация не нуждается в том, что требует интерфейс. Тем не менее, я признаю, что даже если это нарушение, на практике это не является большой проблемой, потому что метод недействителен и по соглашению не должен генерировать/вызывать исключения или сюрпризы в любом случае использования.   -  person Martin Bliss    schedule 02.11.2013
comment
Нарушения @delnan IMO liskov, как правило, следует воспринимать серьезно, поскольку они намекают на рефакторинг в сторону более чистого / более удобного в сопровождении кода, но я полагаю, что теория и практика не могут сойтись в решении в этом случае.   -  person Martin Bliss    schedule 02.11.2013


Ответы (1)


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

Это сложно, но достижимо. Одним из примеров является веб-приложение, когда вы можете ограничить фабричную область действия запросом и безопасно удалить его с активными каталогами, когда запрос будет выполнен. Другой пример — когда ваш экземпляр управляется контейнером IoC, который знает, как работать с IDisposable (для этого у NInject есть несколько хитрых хаков).

Затем, если это не относится к вам, вы должны признать, что универсальное решение не является самым производительным (что совсем не удивительно), и если вы все еще хотите быть абстрактным, вы можете создать дополнительную абстракцию IActiveDirectorySession, которая явно представляет связь сеанс с AD и должен был реализовать IDisposable, по крайней мере, по вполне естественным причинам.

person ovolko    schedule 01.11.2013
comment
Мои мысли точно. Я уже использовал шаблон Ambient Context для создания квази-сеанса, в котором любые объекты, созданные под эгидой службы, регистрируются для удаления при вызове Dispose контекста. Использование IoC для управления временем жизни в этом случае практически невозможно, потому что я считаю неприемлемым открывать сеанс задолго до и закрывать задолго после того, как он необходим. - person Martin Bliss; 02.11.2013