How to modify map element key - language-agnostic

I have a container that holds map of elements.
class MyContainer{
.....
Map<String,MyElement> elements = new ...
...
}
Each element has name property. The key in the map is the element's name. i.e. the method insert is as follows:
void addElement(MyElement elem){
elements.put(elem.getName,elem);
}
I need to use the map data structure, because I have many read operations based on the element name.
The problem is that I need to support modification of the element's name. Changing element name must derive changes in the map. (insert the element with a new key otherwise I won't be able to find that element)
I have thought about two options:
add setName method to MyElement class that will update the container that its name was changed.
don't add setName method to MyElement class, add rename element method to the container, the container will be in charge of updating both the element name and the key in the map.
Option 1 means I have to maintain reference from each element to the container. (this part of the program should maintain low memory footprint).
What do you say? do you see a better option?

I would fire a property change notification on the setName method of the element and handle it in the container object which is listening that notification.

First of all, note that if MyElement can conceivably be used in a context without MyContainer, then option 1 is out.
MyContainer has an obvious relation with MyElement, since its code references MyElement instances through its map. The reverse is not true: the code in MyElement does not need to reference MyContainer. So option 2 is better.
Perhaps, though, you could go for a third hybrid option:
MyElement has a rename method that only changes its own name, and MyContainer has a rename method which calls MyElement.rename and moves the object in the map to the new key.

If the element is only used in this container.
Put the rename operation on the container.
Make the rename method on the element private so another programmer can't accidentally change just the element and forget to update the container.

Option 2 is the simplest and most efficient, thus my choice.
Clearly you know that, so what's the dillema?
Another option is to make a MyString class, that will serve as both a std::string AND a reference to MyContainer. MyString's modifying methods would be in charge of re-maping, and you'd still have a low footprint. E.g.:
class MyString;
class MyElement {
...
MyString name;
...
};
MyContainer * aContainer = new MyContainer;
new MyElement(MyString("Yaron Cohen",aContainer), ...); /* MyString need to be explicit only upon MyElement construction. takes care of inserting into container. */
...
MyElement * someElement = aContainer["Yaron Cohen"]; /* just std::string for lookup */
someElement->name = "Dana International": /* MyString takes care of remapping */
Note that this option supprts multiple keys and containers as well, e.g. FirstName, LastName (if only these were unique...)
Another option is if MyContainer is a singleton.
One more thing to consider is, how often does name change?

Related

Is WindsorContainers AddChildContainer really this bad?

I'm am trying to branch a number of child containers from a basic set of registrations in order to facilitate different configuration settings.
I thought based on Mark Seemanns reply on how child containers work that I could use child containers to override specific components in a base registration. However I does not seem to work as Seemann claims.
According to Mark this should work:
[TestMethod]
public void OverrideRegistrationInParentContainer()
{
//IBusinessComponent depends on IBasicComponent
var parentContainer = new WindsorContainer();
parentContainer.Register(Component.For<IBasicComponent>().ImplementedBy<BasicComponent>()); //Returns 42
parentContainer.Register(Component.For<IBusinessComponent>().ImplementedBy<RealBusinessComponent>()); //Returns the result of IBasicComponent
var childContainer = new WindsorContainer();
childContainer.Register(Component.For<IBasicComponent>().ImplementedBy<BasicComponent2>()); //Returns 40
parentContainer.AddChildContainer(childContainer);
var service = childContainer.Resolve<IBusinessComponent>();
Assert.AreEqual(40, service.GetBusinessValue()); //This fails with the actual value being 42
}
However all dependencies are apparently resolved from the parent.
If i remove the IBasicComponent registration from the parentContainer, I am not even able to resolve the dependency due to missing registrations.
Can anyone explain how you get the container to behave as Seemann claims, or is the WindsorContainer really unable to handle this type of configuration in a graceful manner?
The behavior you're referring to used to work in old Windsor versions but was altered in more recent versions.
Basically this is a bug, and it would allow components from child container to be visible outside its scope (when a component form parent takes a dependency on a component from child)
So the dependencies are allowed to go from child --> parent but not the other way around.

Add a property to a Button or other type of Objects

I always created additional property to MovieCLips using the syntax
myMC.myProperty
without any sort of declaration... But i can use this method only with MovieClips.. What about if i want to add a property to a button or any different type of object? I need to extend the class? Do you can me suggest how? Many thanks
You can add property to movieclips in runtime because MovieClip is dynamic class. If the class is not dynamic, you should extend it to create methods and properties.
Read about dynamic classes.
I tend to create custom classes for nearly everything.
I would extend the relevant class and set up a private var for your new property. You can then pass in the value to the constructor or add a getter/setter method to call externally.
private function _myProperty:int;
public function get myProperty():int
{
return _myProperty;
}
public function set myProperty(newVal:int):void
{
_myProperty = newVal;
}
Getter/setter methods add a few lines of code that may seem unnecessary but on big projects when you find a property is being set and you don't know why, you can put a break point in your set myProperty
Subclass is main solution.
Next works only with mx components (flex sdk 3).
Most components have data : Object property that you can freely use to store data.
Monkey patching sometimes is the only way to go. It allows you to add custom properties to flex sdk classes. I don't think you should use it in your case. But I used it to change core logic that is locked by private keyword in flex sdk.
Hope that helps.

Bindable property change event in Flex

Can anyone please help me solve this mystery:
I've got a component called Box.as that has following two properties, and have their getters & setters defined:
private var _busy:Boolean;
private var _errorMessage:String;
In MXML that uses this component I define it like this:
<components:Box skinClass="skins.components.BoxSkin"
busy="{presenter.boxBusy}"
errorMessage="{presenter.boxErrorMessage}"/>
Where presenter variable is defined here in MXML and a Presenter class has boxBusy and boxErrorMessage variables defined as bindable property change events:
[Bindable(event="propertyChange")]
function get boxBusy():Boolean;
function set boxBusy(value:Boolean):void;
[Bindable(event="propertyChange")]
function get boxErrorMessage():String;
function set boxErrorMessage(value:String):void;
PROBLEM is that whenever I change boxErrorMessage for the presenter, I see the affect in MXML but nothing happens at all when I change boxBusy. Is there something extra I need to do with boolean variable?
Thanks a lot in advance.
You should omit the (event="propertyChange") specification from your [Bindable] metadata tags on both boxBusy and boxErrorMessage. Also, make sure your get/set methods are declared public.
So, the property, boxBusy, would look something like this:
[Bindable]
public function get boxBusy():Boolean { return _busy; }
public function set boxBusy(value:Boolean):void { _busy = value; }
When you qualify [Bindable] with (event="..."), you're telling Flex, "I will dispatch the named event whenever the binding should be updated".
If you omit the event specification, then flex assumes that the event is named propertyChange. But that's not all it does. It also automatically "wraps" your setter with generated code that transparently dispatches a 'propertyChange' event any time the setter is used to modify the value. This is described in more detail here, at adobe livedocs.
So... by explicitly specifying (event="propertyChange"), you disable flex's default behavior. Even though you're using the default event name, flex will not generate the wrapper code -- instead, it will expect you to dispatch the event from your code, at the appropriate time.
I imagine that your boxErrorMessage property appears to be working, because some other [Bindable] property of your class is changing in the same pass -- thus dispatching propertyChange, and causing your boxErrorMessage binding to update as a side-effect.
It is completely possible that if you are setting busyBox to true the first time the setter is getting called but it will not get called again if you again try to set to true. The code that is by the flex compiler when you use the [Bindable] tag will adds a check to see if you are setting the new value to what the getter will currently will return. If that is the cause it isn't called.
If you were to oscillate between true and false it would get called every time because the new value differs from the current value. But setting it to true-true-true-true-false would only result in it getting called the first time to set to your and the last time to set to false.

MooTools - implement element method

var parent = el.getParent();
parent.getElement('div[class=test]'); // return array
var parent1 = el.parentNode;
parent1.getElement('div[class=test]'); // error getElement is not a function
It seems parent1 doesn't have all element methods of MooTools, how to extend all element method of parent1, like in page
Note: I have to use parentNode.
parent.getElement('div[class=test]');
should really be
parent.getElement("div.test");
there's a substantial difference going to element.getParent() and element.parentNode - it boils down to Element prototype, which cannot be extended in old versions of IE.
mootools works around that by saving a reference to the methods directly on the elements instead as properties.
hence if you do element.getParent() and that returns an element, this will extend it to have all the prototypes. element.parentNode returns a simple element object, which will work in browsers where the Element.prototype is inherited correctly.
you can make the second method work in IE by doing:
var parent1 = el.parentNode;
$(parent1).getElement("div.test");
Subsequent references to parent1 do not need the $ (or document.id) as the element will already have been extended.
so to summarize the answer:
to make an element extended, you need to run it through a selector.
var parent = el.parentNode;
$(parent); // this extends it.
parent.getElements("div.test").something()
Both ways work just fine on an element, proof: http://jsfiddle.net/SuJn6/
I assume what you're doing wrong is your el is actually an Element Collection, not a single element. In which case you need to loop your first array, and only then use parentNode, example: http://jsfiddle.net/35Fxf/
Pro-tip: name your variable carefully, el and els - all makes a huge difference.

combining getChildAt with addChild

i have the following code:
seatContainer.getChildAt(order.seats[i])
i want to add a child to this but it doesnt allow me, i can only add an eventListener to this.
Anyone know how i can add a child to this without using an eventListener?
If I remember correctly, getChildAt() from the container classes (e.g. VBox, HBox, etc.) returns a DisplayObject. This object type does not have methods such as "addChild" -- these methods are introduced further down the inheritance hierarchy.
You'll need to cast the referenced returned by the getChildAt() method to something other than DisplayObject; I believe the method you want is in DisplayObjectContainer:
var child:DisplayObject = seatContainer.getChildAt(order.seats[i]);
(child as DisplayObjectContainer).addChild(your_child_class_here);