Python场景下基于Builder设计模式扩展Updater模式实现高效对象更新的方案问询
Great question—you’re absolutely on the right track thinking about extending the Builder pattern here. Let’s walk through a clean Python implementation that checks all your boxes: no broken encapsulation, delegated update logic, and scalability as your class grows.
Core Idea
We’ll create an Updater class (parallel to your original Builder) that:
- Starts with the current state of an existing
Aobject - Lets you chain updates to individual fields (just like the Builder)
- Runs your full validation logic before applying changes
- Safely updates the original object without exposing public setters
Implementation Code
First, we’ll keep class A encapsulated—no public setters, only read-only properties and a protected method to update state (only accessible to our Updater):
class A: def __init__(self, m1, m2): # Internal state remains private self._m1 = m1 self._m2 = m2 # Read-only properties for external access @property def m1(self): return self._m1 @property def m2(self): return self._m2 # Protected method: only trusted classes (like our Updater) should call this def _update_state(self, **kwargs): # Safely update only valid internal fields for field, value in kwargs.items(): internal_field = f"_{field}" if hasattr(self, internal_field): setattr(self, internal_field, value) else: raise ValueError(f"Invalid field for update: {field}")
Next, the AUpdater class—reusing the Builder’s familiar API but tailored to updating existing objects:
class AUpdater: def __init__(self, existing_a: A): # Initialize with the current state of the object self._current_state = { "m1": existing_a.m1, "m2": existing_a.m2 } self._target_object = existing_a # Chainable setters for each field def set_m1(self, m1): self._current_state["m1"] = m1 return self def set_m2(self, m2): self._current_state["m2"] = m2 return self # Reusable validation logic (same as your Builder's _validate) def _validate(self): m1, m2 = self._current_state["m1"], self._current_state["m2"] assert m1 < 1000, "m1 must be less than 1000" assert m1 < m2, "m1 must be less than m2" # Apply validated changes to the original object def apply(self): self._validate() self._target_object._update_state(**self._current_state) return self._target_object
Bonus: Reuse Builder Logic for DRY Code
If you want to share setter and validation logic between your original Builder and the new Updater, extract that into a base class:
class ABasicConfigurer: def __init__(self): self._state = {} def set_m1(self, m1): self._state["m1"] = m1 return self def set_m2(self, m2): self._state["m2"] = m2 return self def _validate(self): m1, m2 = self._state["m1"], self._state["m2"] assert m1 < 1000, "m1 must be less than 1000" assert m1 < m2, "m1 must be less than m2" # Original Builder, now using the base class class ABuilder(ABasicConfigurer): def build(self): self._validate() return A(**self._state) # Updater, reusing the same base logic class AUpdater(ABasicConfigurer): def __init__(self, existing_a: A): super().__init__() self._state = { "m1": existing_a.m1, "m2": existing_a.m2 } self._target_object = existing_a def apply(self): self._validate() self._target_object._update_state(**self._state) return self._target_object
Why This Works for Your Requirements
No Broken Encapsulation:
- Class
Ahas no public setters—external code can only modify state through theAUpdater. - The
_update_statemethod is protected (by Python’s naming convention), so only trusted code (like our Updater) can use it.
- Class
Delegated Update Responsibility:
- All validation and update orchestration lives in
AUpdater, not inAitself. ClassAstays focused on its core responsibilities, not update logic.
- All validation and update orchestration lives in
Maintainable as Complexity Grows:
- Adding a new field only requires:
- Adding it to
A’s__init__ - Adding a
set_xxxmethod to the baseABasicConfigurer - Updating the validation logic once
- Adding it to
- No need to write dozens of combination update methods or a giant "god method"—users can chain any combination of setters they need.
- Adding a new field only requires:
Example Usage
# Create an initial object with Builder a = ABuilder().set_m1(500).set_m2(600).build() print(a.m1, a.m2) # Output: 500 600 # Update it with Updater updated_a = AUpdater(a).set_m1(700).set_m2(800).apply() print(updated_a.m1, updated_a.m2) # Output: 700 800 # Invalid update will fail validation before changing anything try: AUpdater(a).set_m1(1500).apply() except AssertionError as e: print(e) # Output: m1 must be less than 1000
内容的提问来源于stack exchange,提问作者Gulzar

