Все зависит от того, как именно обозначать ответственности компонент в программе. Даже не на уровне кода, а на уровне документации для разработчика/пользователя библиотеки. Вот тот же ResourceManager. Если написано, что ему передается "загрузчик ресурсов", тогда да, эффекты и обертки туда не подходят. А вот если ему передается "сферический поставщик ресурсов в вакууме", тогда и обертки можно делать, и все что угодно. Задача поставщика - "предоставить" ресурс. Будет он при этом обращаться по сети куда-то, просить пользователя нарисовать этот ресурс на экране или еще что-то - в этом случае менеджера не волнует. И фильтры в этом случае тоже подойдут. Фильтры при этом разделяют функциональные аспекты (получение данных, добавление эффектов и т.п), а их композиция все равно имеет одну ответственность "предоставлять данные для менеджера ресурсов" (с поправкой на "роль" этого менеджера в программе).
Psycho Tiger Совсем идеализировать не получится. Всегда можно будет придумать задачу, когда библиотечная реализация будет неудобна. И во многих случаях нужно (или желательно) будет интегрировать код в само приложение. Нужно будет писать либо код конфигурации (если делать прямо в коде), либо конфигуратор по файлу. Для библиотек с хорошим дизайном (все можно конфигурировать, удобно настраивать и т.п.) приходится писать методы "createStandard...". Либо в приложении, либо в библиотеке. Процентов 90 случаев такие методы покроют, в остальных 10 процентах можно будет написать свой аналог конфигурации (собрать по-другому приложение из запчастей). Но здесь опять же без практических задач уже никак.
Да, кроме "один раз создал, и уже клёво" хотелось бы иметь и критерии "эту задачу библиотека не решает"
. Такие критерии позволяют понять, что не стоит пытаться прикрутить библиотеку в неизменном виде, а нужно что-нибудь поменять (или библиотеку, или внешний по отношению к ней код).