views:

64

answers:

5

I want to have 2 static functions called turnOn() and turnOff().

Say objectA calls turnOn(), then objectB calls turnOn(). Then objectA calls turnOff(), it should not turn off because objectB turned it on as well.

Also say objectA calls turnOn(), then objectB calls turnOn(). Then objectB calls turnOff(), it should not turn off because objectA hasn't turned it off yet.

Finally, if objectA and objectB turn it on, it turns off when they both turn it off.

I was thinking keeping track of how many turnOn and TurnOff's are called and make sure it matches, but thats not truly accurate because objectA can call turnOff() twice.

So whats the best sort of way to handle this?

Thanks!

+1  A: 

This sounds like reference counting

Draemon
+1  A: 

The simplest method is as you describe: keep a count. If you're really concerned with an object turning it off when it hasn't turned it on, you can keep a list of all objects that have turned it on, and remove them from the list when they turn it off. If the list is empty, you can actually turn it off.

Pesto
Does AS3 have sets or hashtables? That would be better than a plain list
Draemon
@Draemon: Perhaps, provided that a single object can't call turnOn twice. If you have to allow multiple turnOn/turnOff pairs from a single object, you'll probably want some sort of sorted list. Not necessarily a linked list, mind you.
Pesto
hastable(object, count) then. Anything you can do lookups on very quickly is fine. Linked list would be bad since it would reduce you to a linear search.
Draemon
List != Linked List. I don't care how you back the data structure, it just has to be something with `contains` and `find` methods.
Pesto
A: 

Edit: The example code is in c# -- I didn't realize this wasn't a c# question. If you have hashtables, dictionaries, or even 2-d arrays (tables) in your language, this same basic pattern should still work.

It sounds like you need a modified sort of ref count -- a count that goes by object. How about something like this:


public class Switch
{
  private bool On;
  private Dictionary<object, int> ReferenceCounts = new ...
  public void TurnOn(object source)
  {
     int count = 0;
     if(ReferenceCounts.ContainsKey(source))
        count = ReferenceCounts[source];
     count++;
     ReferenceCounts[source] = count;
     On = true;
  }

  public void TurnOff(object source)
  {
    if(!ReferenceCounts.ContainsKey(source))
       return;

    int count = ReferenceCounts[source];
    count--;
    if(count == 0)
      ReferenceCounts.Remove(source)
    else
      ReferenceCounts[source] = count;

    if(ReferenceCounts.Count == 0)
      this.On = false;
  }
}

JMarsch
(note, you didn't mention whether ObjectA and B could be on multiple threads. If they are, you will need to add appropriate synchronization code.
JMarsch
(sorry -- I just realized that you are on an AS3 tag (I thought I had filtered to c# -- this is c# code. If as3 has dictoinaries or hash tables, this should work --- you could probably even make it work with a 2-dimensional array.
JMarsch
Thanks AS3 does have dictionaries, I haven't used them yet, will try this out, trying to understand it now. Thanks!
John Isaacks
Good luck! I left out the usage. ObjectA would call TurnOn like this: switch.TurnOn(this) (this/self/me, whatever an AS3 means that objectA is passing itself to TurnOn). Switch keeps track of which objects have called turn on, and only turns itself off if all objects that called turn on have called turnoff. the dictionary keeps a count of who has turned the switch on indexed by the object that called TurnOn.
JMarsch
A: 

I'm not 100% sure this is what you're looking for but I think you'll want to have a static array to determine what is on or not. Also... fair warning, I didn't test this code. This is a very rough estimate of what I thought you might be looking to do.

class Switchable {
    static var _onObjects:Array=new Array  ;
    static public  function turnOn(obj:Object):Void {
     if (_onObjects.indexOf(obj) == -1) {
      _onObjects.push(obj);
     }
    }
    static public  function turnOff(obj:Object):Void {
     var index=_onObjects.indexOf(obj);
     if (isOn() && index >= 0) {
      _onObjects=_onObjects.splice(index,1);
     }
    }
    static public  function isOn():Boolean {
     return _onObjects.length > 0;
    }
}
class ObjectA {
    public function Foo():Void {
     Switchable.turnOn(this);
    }
    public function Bar():Void {
     Switchable.turnOff(this);
    }
}
class ObjectB {
    public function Foo():Void {
     Switchable.turnOn(this);
    }
    public function Bar():Void {
     Switchable.turnOff(this);
    }
}
class Test {
    static public  function Main():Void {
     trace(Switchable.isOn());
     var a:ObjectA=new ObjectA  ;
     var b:ObjectB=new ObjectB  ;
     a.Foo();
     trace(Switchable.isOn());
     b.Foo();
     trace(Switchable.isOn());
     a.Bar();
     trace(Switchable.isOn());
     b.Bar();
     trace(Switchable.isOn());
    }
}
blesh
A: 

The solution has two parts: - a static object counter, as suggested elsewhere, - and a per-object isTurnedOn flag that prevents turning the object on or off twice, something along the lines of this pseudo-code:

...
private static in count = 0;
private boolean isTurnedOn = false;
...
public void TurnON() {
    if (!isTurnedOn) {
        isTurnedOn = true;
        ++count;
    }
}

public void TurnOff() {
    if (isTurnedOn) {
        isTunedOn = false;
        --count;
        if (count == 0) {
            // the conter reached 0, do soemthing
            // but do not forget to protect against concurretn access
    }
 }

Please note that this construct allows turning the object repeatedly on and off. If you want to prevent this, probably you should use two separate booleans for isTurnedOn and isTurnedOff.