Предполагая, что вы не ищите насмешливые рамки, потому что они ультра-вездесущи и их легко найти , есть несколько вещей, на которые стоит обратить внимание:
- Есть «никогда», что вы должны «всегда» делать.
Не всегда лучше завернуть стороннюю библиотеку. Если ваше приложение по своей природе зависит от библиотеки, или оно буквально построено на одной или двух основных библиотеках, не тратьте свое время на его завершение. Если библиотеки меняются, ваше приложение должно будет измениться в любом случае.
- Можно использовать интеграционные тесты.
Это особенно верно в отношении границ, которые являются стабильными, присущими вашему приложению или не могут быть легко смоделированы. Если эти условия будут выполнены, упаковка и насмешка будут сложными и утомительными. В этом случае я бы избегал и того и другого: не оборачивайся и не издевайся; просто напишите интеграционные тесты. (Если целью является автоматизированное тестирование.)
- Инструменты и структура не могут устранить логическую сложность.
В принципе, инструмент можно вырезать только на шаблоне. Но нет автоматизируемого алгоритма, позволяющего взять сложный интерфейс и сделать его простым - не говоря уже о том, чтобы взять интерфейс X и адаптировать его под свои нужды. (Только вы знаете этот алгоритм!) Итак, хотя есть, несомненно, инструменты, которые могут генерировать тонкие обертки, я бы предположил, что они еще не вездесущи, потому что, в конце концов, вам все равно нужно просто разумно кодировать и, следовательно, вручную, против интерфейса, даже если он скрыт за оболочкой.
Тем не менее, есть тактика, которую вы можете использовать на многих языках, чтобы избежать прямого обращения к классу. А в некоторых случаях вы можете «симулировать» интерфейс или тонкую оболочку, которой на самом деле не существует. В C #, например, я бы пошел одним из двух маршрутов:
- Используйте фабричную и неявную типизацию .
Вы можете избежать усилий, чтобы полностью обернуть сложный класс с этим небольшим комбо:
// "factory"
class PdfDocumentFactory {
public static ExternalPDFLibraryDocument Build() {
return new ExternalPDFLibraryDocument();
}
}
// code that uses the factory.
class CoreBusinessEntity {
public void DoImportantThings() {
var doc = PdfDocumentFactory.Build();
// ... i have no idea what your lib does, so, I'm making stuff but.
// but, you can do whatever you want here without explicitly
// referring to the library's actual types.
doc.addHeader("Wee");
doc.getAllText().makeBiggerBy(4).makeBold().makeItalic();
return doc.exportBinaryStreamOrSomething();
}
}
Если вы можете избежать сохранения этих объектов как членов, либо с помощью более «функционального» подхода, либо путем сохранения их в словаре (или чего- либо еще ), этот подход имеет преимущество проверки типов во время компиляции без необходимости точно знать ваши основные бизнес-сущности. с каким классом они работают.
Все, что требуется, это то, что во время компиляции класс, возвращаемый вашей фабрикой, на самом деле имеет методы, которые использует ваш бизнес-объект.
- Используйте динамическую типизацию .
Это в том же духе, что и при использовании неявной типизации , но включает другой компромисс: вы теряете проверки типа компиляции и получаете возможность анонимно добавлять внешние зависимости в качестве членов класса и вводить ваши зависимости.
class CoreBusinessEntity {
dynamic Doc;
public void InjectDoc(dynamic Doc) {
Doc = doc;
}
public void DoImortantThings() {
Doc.addHeader("Wee");
Doc.getAllText().makeBiggerBy(4).makeBold().makeItalic();
return Doc.exportBinaryStreamOrSomething();
}
}
При использовании обеих этих тактик, когда приходит время высмеивать ExternalPDFLibraryDocument
, как я уже говорил ранее, вам есть над чем работать, но эту работу вам все равно придется выполнять . И с этой конструкцией вы избежали утомительного определения сотен классов тонких маленьких упаковщиков. Вы просто использовали библиотеку, не глядя прямо на нее - по большей части.
Учитывая все вышесказанное, есть три основные причины, по которым я бы по-прежнему рассматривал явное завершение работы сторонней библиотеки - ни одна из которых не намекала бы на использование инструмента или инфраструктуры:
- Конкретная библиотека не является неотъемлемой частью приложения.
- Было бы очень дорого поменять местами, не оборачивая его.
- Мне не нравится сам API.
Если у меня нет какой-либо озабоченности по поводу уровня во всех этих трех областях, вы не приложите каких-либо значительных усилий, чтобы завершить ее. И, если у вас есть проблемы во всех трех областях, автоматически созданная тонкая оболочка не поможет.
Если вы решили обернуть библиотеки вверх, наиболее эффективное и эффективное использование вашего времени , чтобы построить приложение от интерфейса вы хотите ; не против существующего API.
Иными словами, прислушайтесь к классическому совету: отложите каждое решение, которое сможете. Сначала создайте «ядро» вашего приложения. Код против интерфейсов, который в конечном итоге будет делать то, что вы хотите, что в конечном итоге будет выполнено "периферийными устройствами", которые еще не существуют. Устраните пробелы по мере необходимости.
Это усилие может не показаться сэкономленным временем; но если вы чувствуете, что вам нужна обертка, это самый эффективный способ сделать это безопасно.
Думайте об этом так.
Вам нужно кодировать эту библиотеку в каком-то темном углу вашего кода - даже если она обернута. Если вы будете издеваться над библиотекой во время тестирования, это неизбежно приведет к ручным усилиям, даже если она будет завершена. Но это не означает, что вам нужно напрямую подтверждать эту библиотеку по имени во всем объеме вашего приложения.
TLDR
Если библиотека заслуживает того, чтобы ее обернуть, используйте тактику, чтобы избежать широко распространенных прямых ссылок на вашу стороннюю библиотеку, но не используйте ярлыки для создания тонких оболочек. Сначала создайте свою бизнес-логику, продумайте свои интерфейсы и, при необходимости , разрабатывайте свои адаптеры органично .
И, если дело доходит до этого, не бойтесь интеграционных тестов. Они немного размыты, но они все еще предлагают доказательства работы кода, и их все еще легко можно сделать, чтобы держать регрессии в страхе.