You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用真实数据的Builder模式:控制器作为指挥者是否违反设计原则?

Is Passing Real Data from MVC Controller to Builder Violates Builder Pattern Principles?

Great question! Let me reassure you first: your approach does NOT violate the Builder pattern's design principles — in fact, this is exactly how the pattern is meant to be used in real-world applications.

Let’s break down why this is perfectly valid:

1. Builder’s core isn’t about hardcoding values

Tutorials use hardcoded strings like setFoo("hardcoded value") purely for simplicity, to focus on explaining the pattern’s structure. The whole point of the Builder pattern is to let you dynamically configure objects with any data source — whether it’s a database, user input, API responses, or (like your case) data fetched in an MVC controller.

2. Using a controller as the Director makes sense

The Builder pattern often includes a "Director" role: a component that controls the construction flow, deciding which properties to set and with what values. Your MVC controller fits this role perfectly: it’s responsible for gathering the necessary data (from the database, in your example) and directing the Builder to assemble the final object. This separation of concerns is exactly what the pattern encourages.

3. Key things to keep in mind (to stay true to the pattern)

To make sure you’re using Builder optimally:

  • Enforce immutability (if desired): If your goal is to create immutable objects (a common use case for Builder), ensure the final object has no setters, and the Builder only passes values to the object’s private constructor.
  • Keep the Builder focused: Don’t add business logic to the Builder — its sole job should be collecting values and constructing the object. Leave data fetching and validation (beyond basic checks like non-null required fields) to the controller or service layer.
  • Use method chaining (optional but clean): Modify your Builder’s setters to return the Builder instance itself, which makes the code more readable (like fooBuilder.setBar(data).setFoo(moreData).build()).

Example of a clean implementation with real data

// Immutable Foo class
public class Foo {
    private final String bar;
    private final String foo;

    // Private constructor to enforce Builder usage
    private Foo(FooBuilder builder) {
        this.bar = builder.bar;
        this.foo = builder.foo;
    }

    // Getters only (no setters for immutability)
    public String getBar() { return bar; }
    public String getFoo() { return foo; }

    public static class FooBuilder {
        private String bar;
        private String foo;

        // Chained setters return the Builder instance
        public FooBuilder setBar(String bar) {
            this.bar = bar;
            return this;
        }

        public FooBuilder setFoo(String foo) {
            this.foo = foo;
            return this;
        }

        // Build method with basic validation
        public Foo build() {
            if (bar == null || bar.isBlank()) {
                throw new IllegalArgumentException("Bar cannot be empty");
            }
            return new Foo(this);
        }
    }
}

// MVC Controller acting as Director
@Controller
public class FooController {
    private final FooDataService dataService;

    // Constructor injection (dependency injection best practice)
    public FooController(FooDataService dataService) {
        this.dataService = dataService;
    }

    @GetMapping("/create-foo")
    public ResponseEntity<Foo> createFoo() {
        // Fetch real data from database via service
        String barData = dataService.fetchBarFromDb();
        String fooData = dataService.fetchFooFromDb();

        // Direct the Builder to construct the Foo object
        Foo finalFoo = new Foo.FooBuilder()
                .setBar(barData)
                .setFoo(fooData)
                .build();

        return ResponseEntity.ok(finalFoo);
    }
}

Final takeaway

Your approach is aligned with the Builder pattern’s core goals: separating object construction from its representation, allowing flexible configuration, and ensuring clean, readable code. The hardcoded values in tutorials are just a teaching tool — real-world usage relies on dynamic data inputs like the ones you’re using.

内容的提问来源于stack exchange,提问作者john

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:51:00