Question

I have an object Foo that has 2 public properties: A and B.

These properties can be changed from outside, as the application I'm working on is using a data-binding architecture. This is the front-end (client) code, but it's also communicating with a server to fetch data.

So my object is listening for changes to both A and B.

Any change in A or B is triggering the update() method, which triggers a request to the server.

I also have a piece of logic in my object Foo that says every time you change B, you have to reset A to its initial value.

My problem is, how do I deal with updating B without triggering the update() method twice?

enter image description here

Looking at the image above, the green path should always trigger an update. The red path ends up sometimes triggering 2 updates, because by changing B it changes A (if it's not the initial value), which always triggers an update.

I have to add that everything is asynchronous so the observers for my properties don't notify me immediately after changing objects. (design choice of the platform and language I'm working in – Polymer.JS). So this makes it harder to set a flag before changing B from A - I tried this but it didn't work, as the watcher method gets triggered after the chain of changes has executed.

As I come from the front-end world, with a background in graphic design, I don't have the knowledge necessary to spot the mistakes I might be doing, but I want to learn, so I'd like you to point me to reference material and/or books I can read about the correct applications of the observer pattern.

Is there a pattern that deals with this particular scenario and what are possible solutions to this?

If the observer pattern isn't the right choice for this, is there another pattern I could use internally that allows me to expose only the two properties A and B to the outside world?

A third option would be that I'm applying the right pattern, but the platform doesn't support what I'm trying to achieve. I'd like to know this so I can post the question on StackOverflow under the right tags.

Était-ce utile?

La solution

You make a special message to A that changes it in a way that is not propagated. Its a common idiom where you want general updates to send notifications, but not internal updates or refreshes.

For example, I have a dialog that has notification handlers for changes to various controls, but in the initialisation I want to set the controls initial state - without sending these notifications. In this case, I simply set an 'initialising' flag that the notification handler checks for, if its set the handler simply does nothing.

If you cannot set a flag to change the state of A to prevent notification, then you will have to send it with the change message. So you have 2 messages, one to update A (the general case) and another to quietly change A that is sent by B but still allows for changes to A to be triggered when others change it. I don't know how you make these updates so the implementation specifics is up to you.

Autres conseils

Generally you would have values A and B hidden using a mixin, changeable only through a method setA and setB (or better still by using a setter function). Internally, you would simply assign A or B directly without calling the setA or setB directly, and then call update() which triggers the event.

In other words, you'd have setA that assigns A and then resets the value of B without calling setB. Take a look at this quick example:

function Obj() {
  var A, B;

  function resetB() {
    console.log('Resetting B');
    B = '';
  }
  function update() {
    console.log('Values updated');
  }
  return {
    get A() { return A; },
    get B() { return B; },
    set A(aVal) { 
      A = aVal; 
      resetB(); 
      update();
    },
    set B(bVal) { 
      B = bVal;
      update(); 
    }
  };
}
var obj = new Obj();
obj.B = 'test';
// Console output:
// Values updated

// assert(obj.B == 'test')
obj.A = 'me';
// Console output:
// Resetting B
// Values updated

// assert(obj.A == 'me')
// assert(obj.B == '')
Licencié sous: CC-BY-SA avec attribution
scroll top