Hollywood Principle
Definition

Traditional vs Hollywood
// TRADITIONAL: Your code controls flow
public class ReportGenerator {
public void generateReport() {
DataLoader loader = new DataLoader();
Formatter formatter = new Formatter();
Printer printer = new Printer();
Data data = loader.load(); // You call
String formatted = formatter.format(data); // You call
printer.print(formatted); // You call
}
}
// HOLLYWOOD: Framework controls flow
public abstract class ReportTemplate {
// Template method - framework controls flow
public final void generateReport() {
Data data = loadData(); // Framework calls you
String formatted = formatData(data); // Framework calls you
outputReport(formatted); // Framework calls you
}
// Your code - called by framework
protected abstract Data loadData();
protected abstract String formatData(Data data);
protected abstract void outputReport(String report);
}
public class SalesReport extends ReportTemplate {
@Override
protected Data loadData() {
return salesDatabase.query();
}
@Override
protected String formatData(Data data) {
return new SalesFormatter().format(data);
}
@Override
protected void outputReport(String report) {
emailService.send(report);
}
}
Framework Examples
// Spring Framework - classic Hollywood principle
// You provide the component
@Service
public class OrderService {
private final OrderRepository repository;
// Spring calls your constructor
public OrderService(OrderRepository repository) {
this.repository = repository;
}
public void processOrder(Order order) {
repository.save(order);
}
}
// You don't control when OrderService is created
// You don't control when repository is injected
// Spring framework controls all of that - "we'll call you"
// Event handling - another example
// Traditional: You poll for events
while (true) {
Event event = checkForEvent(); // You're calling
if (event != null) {
handleEvent(event);
}
Thread.sleep(100);
}
// Hollywood: Register handler, framework calls you
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
// Framework calls this when event occurs
sendConfirmationEmail(event.getOrder());
}
// Servlet example
public class MyServlet extends HttpServlet {
// Container calls this - you don't call main() or anything
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
// Your code, called by container
}
}
Callback Pattern
// Callbacks are Hollywood Principle in action
// Traditional: Synchronous, you wait
public class FileProcessor {
public String processFile(String path) {
byte[] content = readFile(path); // Blocks
String result = transform(content); // Blocks
return result;
}
}
// Hollywood: Callback, framework calls you when done
public class AsyncFileProcessor {
public void processFile(String path, Consumer<String> callback) {
executor.submit(() -> {
byte[] content = readFile(path);
String result = transform(content);
callback.accept(result); // We call you when ready
});
}
}
// Usage
processor.processFile("data.txt", result -> {
// This gets called when processing is done
System.out.println(result);
});
// CompletableFuture example
public CompletableFuture<Order> fetchOrder(String orderId) {
return CompletableFuture.supplyAsync(() -> {
return orderClient.fetch(orderId);
});
}
// Your handlers called when futures complete
fetchOrder("123")
.thenApply(this::enrichOrder) // Called when fetch completes
.thenApply(this::validateOrder) // Called when enrich completes
.thenAccept(this::processOrder) // Called when validate completes
.exceptionally(this::handleError); // Called on any error
Template Method Pattern

Real-World Applications
// JUnit - framework calls your tests
public class OrderServiceTest {
@BeforeEach
void setup() {
// JUnit calls this before each test
}
@Test
void shouldCreateOrder() {
// JUnit calls this
}
@AfterEach
void cleanup() {
// JUnit calls this after each test
}
}
// Spring MVC - framework calls your controller
@RestController
public class OrderController {
@GetMapping("/orders/{id}")
public Order getOrder(@PathVariable String id) {
// Spring calls this when request matches
return orderService.findById(id);
}
}
// Reactive Streams - operators called by publisher
Flux.fromIterable(orders)
.filter(Order::isPending) // Called by framework per item
.map(this::enrich) // Called by framework per item
.flatMap(this::process) // Called by framework per item
.subscribe(this::onComplete); // Called when done
// JavaFX/Swing - GUI framework calls your handlers
button.setOnAction(event -> {
// Framework calls this when button clicked
processAction();
});
Benefits and Trade-offs

Tips & Tricks
