简体   繁体   中英

What design pattern does this?

I did this once a long time ago and followed a design pattern when I did. Now, I need to do it again, I don't really remember how I did it before, and I can't think of the pattern that helped me do it.

I have a class with a whole slew of variables/properties. Some are calculated based on the others, and there is all sorts of cross-calculating going on between these properties.

It's all fine when I first instantiate - all the values and the calculations work just fine. My problem is, when one value changes, I want all of the calculated values derived from it to update themselves based on the new value automatically. And I don't want to write each individual recalc manually if I don't have to - it just becomes a lot of overhead whenever this class gets updated or added to, trying to track down all of the places you need to propagate whatever change you're making.

I think you follow me.

Anyway, can anyone think of what pattern it is that makes this possible? I swear I used to know it. Getting old I guess.

// Like this...
class foo
{
    decimal A = 1233;
    decimal B = 42;

    decimal C = A / B; // I want this to update whenever
                       // the value of either A or B changes.
    decimal D = 123;
    decimal E = 321;

    decimal F = D + E; // I don't want this one to change when
                       // A or B or even C for that matter changes,
                       // and I don't wan to have to cycle through
                       // all of the calculated values that don't
                       // need to change just for find the few that do.
}

Observer. You need some kind of .Subscribe() method on your models that is used to register callbacks - in your specific cases those are just functions that take new value and recompute some others based on that one. As long as your programming environment has rxjs implementation(s), I strongly suggest to stick to that one. Otherwise you'll suffer because of multithreading and memory leaks.

I'd suggest to avoid over-engineering here. What you presented as an example has 6 members with simple dependencies between them that can be easily recalculated. I do understand this can be just a simplified example, so let's aim for eg 10-20 members, and dependencies that don't require database lookups or disk access (as an example of heavier operations).

You can put all dependencies into one method (let's call it Update ), which you call if any member is modified. To not worry about remembering to call Update() , you move all members into a separate "state" class:

class FooState
{
    private int _a;

    public int A
    {
        get { return _a; }
        set
        {
            _a = value;
            Update();
        }
    }

    private int _b;

    public int B
    {
        get { return _b; }
        set
        {
            _b = value;
            Update();
        }
    }

    public double C { get; private set; }

    // other members

    private void Update()
    {
        C = A * B + 3;
        // other updates
    }
}

class Foo
{
    private FooState _state;

    public Foo()
    {
        _state.A = 1;
        _state.B = 2;
        Debug.Write($"C = {_state.C}");
    }
}

What you get:

  • It's immediately clear what's going on. To anybody who will happen to modify this code.
  • all dependencies between your members are in a single method, easy to read, easy to modify. Your business logic is not polluted with this details.
  • You can't forget to recalculate your dependent members.
  • Yes you can do more recalculation than strictly required, as you recalculate all your dependent members even if an unrelated member was modified. In the majority of similar cases I've seen in real file this wasn't a problem.
  • This approach doesn't work if you have cyclic dependencies (which is a different story).

Feel free to implement "observer" pattern and compare.

I don't think this simple approach has the name. Don't confuse it with "State" pattern which is a bit different thing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM