Skip to content

Hollywood Principle


Definition

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

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

Benefits and Trade-offs


Tips & Tricks

Tips and Tricks