Продолжая ответ Адриана, я кратко объясню, как это будет работать:
Предположим, что DataBlock происходит от интерфейса с именем IDataBlock. Каждый расширитель наследуется от DataBlockDecorator, который наследуется от IDataBlock, который выполняет некоторую операцию с DataBlock (принимая IDataBlock в конструкторе). Это позволяет вам делать что-то вроде.
IDataBlock block = new DataBlock();
for (DataBlockDecorator extender : this.getExtenders()) {
extender.extend(block);
block = extender;
}
Однако, это на самом деле не добавляет больше гибкости, чем раньше. В этом отношении ваше оригинальное решение уже настолько гибко, насколько оно возможно.