How to avoid circular dependencies when setting Properties?

前端 未结 2 1944
清酒与你
清酒与你 2021-01-21 09:12

This is a design principle question for classes dealing with mathematical/physical equations where the user is allowed to set any parameter upon which the remaining are being ca

2条回答
  •  失恋的感觉
    2021-01-21 09:30

    I would recommend to teach your application what can be derived from what. For example, a typical case is that you have a set of n variables, and any one of them can be derived from the rest. (You can model more complicated cases as well, of course, but I wouldn't do it until you actually run into such cases).

    This can be modeled like this:

    # variable_derivations is a dictionary: variable_id -> function
    # each function produces this variable's value given all the other variables as kwargs
    class SimpleDependency:
      _registry = {}
      def __init__(self, variable_derivations):
        unknown_variable_ids = variable_derivations.keys() - self._registry.keys():
          raise UnknownVariable(next(iter(unknown_variable_ids)))
        self.variable_derivations = variable_derivations
    
      def register_variable(self, variable, variable_id):
        if variable_id in self._registry:
          raise DuplicateVariable(variable_id)
        self._registry[variable_id] = variable
    
      def update(self, updated_variable_id, new_value):
        if updated_variable_id not in self.variable_ids:
          raise UnknownVariable(updated_variable_id)
        self._registry[updated_variable_id].assign(new_value)
        other_variable_ids = self.variable_ids.keys() - {updated_variable_id}
        for variable_id in other_variable_ids:
          function = self.variable_derivations[variable_id]
          arguments = {var_id : self._registry[var_id] for var_id in other_variable_ids}
          self._registry[variable_id].assign(function(**arguments))
    
    class FloatVariable(numbers.Real):
      def __init__(self, variable_id, variable_value = 0):
        self.variable_id = variable_id
        self.value = variable_value
      def assign(self, value):
        self.value = value
      def __float__(self):
        return self.value
    

    This is just a sketch, I didn't test or think through every possible issue.

提交回复
热议问题