Instantiate and extend models

JeffW.'s Avatar

JeffW.

24 Jun, 2013 05:01 PM

hi,

I'm trying to work with a model and extending it.

When say ModelSub extends ModelSuper and I override say function setSomeVar which
sets a var in ModelSuper, the var in ModelSuper is not being set.

I think this has to do with how I instantiate the model(s).

Usually, in a non rl project, I would say smt like:

var model:ModelSuper = new ModelSub();
model.setVar("hey");
and the var would be set in ModelSuper.

How do I inject and/or instantiate a sub model in rl to make this work?

I am now just doing:

context.injector.map( MyModel ).asSingleton();
but I think that is not enough?

thanks,
Jeff.

  1. 1 Posted by JeffW. on 25 Jun, 2013 08:14 AM

    JeffW.'s Avatar

    I guess I need to use interfaces, sth like described here:
    http://knowledge.robotlegs.org/discussions/questions/166-map-multip...

    But I don't see how exactly. Do both super and sub model need their own interface?
    What do I add in my configure function so that I can inject them in for instance commands? How do you map a model to its interface in RL2?

    Tried some things like this:

    context.injector.map( ModelSub ).asSingleton();
    context.injector.map( ModelSuper ).asSingleton();
    
    context.injector.map(IModelSub).toSingleton( ModelSub) 
    context.injector.map(IModelSuper).toSingleton( ModelSuper)
    
    but these are just wild guesses that don't work..
  2. 2 Posted by JeffW. on 25 Jun, 2013 08:20 AM

    JeffW.'s Avatar

    Actually I can set a var in the supermodel from an overridden function in sub model now, so that is not the problem. The question is how I can access that var in another command by injecting the model or its interface...

  3. Support Staff 3 Posted by Ondina D.F. on 25 Jun, 2013 08:56 AM

    Ondina D.F.'s Avatar

    Hold on, I'll be with you in a bit.

  4. Support Staff 4 Posted by Ondina D.F. on 25 Jun, 2013 09:11 AM

    Ondina D.F.'s Avatar

    Using a base class

    Mapping

    injector.map(SomeModel).asSingleton();
    

    SomeModel

    public class SomeModel extends BaseModel
    {           
        public function doSomething():void
        {
            someProperty = someProperty+" modified in SomeModel";         
        }
    }
    

    BaseModel

    public class BaseModel
    {
        private var _someProperty:String;
    
        public function BaseModel()
        {
        }
    
        public function set someProperty(value:String):void
        {
           _someProperty = value;
        }
    
        public function get someProperty():String
        {
            return _someProperty;
        }
    }
    

    SomeClass

    [Inject]
    public var someModel:SomeModel;
    
    private function someMethod():void
    {
        someModel.someProperty = "some value";
    }
    private function anotherMethod():void
    {
        trace(someModel.someProperty); //traces "some value"
    }
    

    Somewhere, call someMethod(); then anotherMethod();

    AnotherClass

    [Inject]
    public var someModel:SomeModel;
    
    private function execute():void
    {
        someModel.doSomething();
        trace(someModel.someProperty); //traces "some value modified in SomeModel"
    }
    

    Using Interfaces:

    Mapping:

    injector.map(ISomeOtherModel).toSingleton(SomeOtherModel);
    

    ISomeOtherModel

    public interface ISomeOtherModel
    {
        function doSomething():String;
    }
    

    SomeOtherModel

    public class SomeOtherModel implements ISomeOtherModel
    {
        public function SomeOtherModel()
        {
        }
        public function doSomething():String
        {
            return "done something";
        }
    }
    

    SomeClass

    [Inject]
    public var someOtherModel:ISomeOtherModel;
    
    private function someOtherMethod():void
    {
        var someString:String = someOtherModel.doSomething();
        //someString is "done something"
    }
    
  5. Support Staff 5 Posted by Ondina D.F. on 25 Jun, 2013 10:09 AM

    Ondina D.F.'s Avatar

    If IModel is the interface having a var someProperty:String; and someMethod();, implemented by ModelA and ModelB, then you’ll have to map ModelA

    injector.map(IModel).toSingleton(ModelA); in Module A

    and

    injector.map(IModel).toSingleton(ModelB); in Module B

  6. 6 Posted by JeffW. on 25 Jun, 2013 10:12 AM

    JeffW.'s Avatar

    thanks Ondina, this looks clear to me, and I actually have tried it this way with various results. I looked at my code again and what I'm picturing is that I have common code for multiple contexts. And that I sometimes want to extend this code - a model, command or view - and sometimes not. If I extend a class I can inject the extended class as you describe.

    Suppose I have a command that I don't want to extend. I just want to inject the super model into that . This also works - since 1 minute ago - but only if I also map the super model in my config. It feels funny to map both super and sub model. Is this where some smart way of working with interfaces comes in? Something like implementing the interface of a super model onto a sub model.

  7. Support Staff 7 Posted by Ondina D.F. on 25 Jun, 2013 10:25 AM

    Ondina D.F.'s Avatar

    I’m trying to understand your use case. (reading your questions from the other post and this one). I’m not quite sure what you want to achieve.

    The common class would be the interface, IModel, that can reside in a lib, or in the commons folder of the app. In Module A you have ModelA implementing IModel, and in Module B ModelB implementing IModel, both sharing someProperty and someMethod(), and each having (or not) other properties or methods of their own.

    The other thing you’re talking about is how to let the shell know about properties changed in ModuleA or B, and/or how to pass this properties from a module to another, right?
    You’re talking about a SuperModel or something, but you mean a Shell’s model right?

  8. Support Staff 8 Posted by Ondina D.F. on 25 Jun, 2013 10:29 AM

    Ondina D.F.'s Avatar

    Maybe what you want is ModuleA dispatching an event to trigger a command in the Shell, which would then set properties on a ModulesModel (your super model?). Then ModuleB, when loaded, would dispatch an event to trigger another command of the Shell, to get the properties from ModulesModel?

  9. 9 Posted by JeffW. on 25 Jun, 2013 10:37 AM

    JeffW.'s Avatar

    Sorry if I'm not clear, which I can imagine.

    No, I'm not talking about a shell model, not worried about that at the moment.
    I'm talking about a base model that holds functions and properties used by both modules. In my eyes an interface would just contain a list of functions that the module models need to implement whereas a base model, well, contains the actual shared functions and properties. I was hoping to somehow access that base model in a command so that I don't need to write a sub command for every module with its own model injected.

  10. Support Staff 10 Posted by Ondina D.F. on 25 Jun, 2013 01:18 PM

    Ondina D.F.'s Avatar

    Sorry for the delay, stuff related to my personal projects has been keeping me busy.

    What you’re saying is that you want to modify properties in a BaseClass and are expecting that the derived classes would reflect the changes? That’s not possible.

    I might be wrong, but I think that you want something like the decorator pattern?

  11. 11 Posted by JeffW. on 25 Jun, 2013 01:52 PM

    JeffW.'s Avatar

    Always glad you answer my posts, no matter if it takes a little longer:)

    I don't think I'm expecting derived classes to reflect changes in the BaseModel.
    Say I have a BaseModel that reside in my common lib. I want to extend it because there are some differences in how Module A and B save data into the model. So I create ModelA and ModelB, both extending BaseModel.

    What I'm trying to avoid is to inherit each and every command that resides in the common lib just to be able to inject ModelA into MyCommandA and ModelB into MyCommandB, which both extend MyCommand. Because what if there is no difference between these 'sub' commands? Then I would just like to use MyCommand. But I cannot inject both ModelA and ModelB into MyCommand. So I was hoping to somehow inject BaseModel or some interface into MyCommand and have access to changes made in ModelA or ModelB. Maybe it's more the other way around: I'm expecting BaseModel to reflect changes in the derived classes.

    Is this possible you think? Because if not, I would need to extend all the base commands, even if they are similar for A and B, just to inject ModelA and ModelB.

  12. Support Staff 12 Posted by Ondina D.F. on 25 Jun, 2013 03:03 PM

    Ondina D.F.'s Avatar

    Hehe, Jeff. The other way around wouldn’t work either.

    One thing to notice is that ModelA and ModelB could implement different interfaces, even if they extend a BaseModel. Also, as you’ve noticed, ModelA and ModelB can have their own methods in addition to the ones inherited from a BaseModel.

    Or, ModelA and ModelB implement the same interface, and you’d inject the interface into the classes that need them.
    In ModuleA, you mapped it like this: injector.map(IModel).toSingleton(ModelA); and you inject it like this:
    [Inject] public var model:IModel; //an instance of ModelA will be used

    So a command wouldn’t have to know anything about the concrete classes, if you injected the interface.

    Also, a class can implement more than one interface, as you probably know.

    Another thing is that of what a sub-context inherits from its parent.
    Say, you have a mapping in the parent:

    injector.map(SomeCrazyClass).asSingleton();

    If you use the ModularityExtension without modifying its default settings (ModularityExtension(inherit:Boolean = true, expose:Boolean = true)), then
    a sub-context will inherit the mapping of SomeCrazyClass, and you could inject it into your sub-context’s classes.

    If you don’t want a sub-context to inherit from its parent, you configure it like this:
    .install(MVCSBundle, new ModularityExtension(false))

    In this case you have to map SomeCrazyClass in the sub-context.

    Also, even if you mapped it in the parent context, and you used the default inherit:Boolean = true, if you map it in the sub-context, the subcontext will use its own mappings.

    I just wanted to mention all this, just in case you didn’t know how subcontexts inherit from parent. So, sorry in case you knew.

    Now, after that much back and forth I don’t know anymore what to say and I feel like I’m missing your point entirely. I’m getting dizzy ;)
    I think it would be easier to attach an example of what you’re trying to achieve, and I could tell you which solution I’d choose after looking at your classes.

  13. 13 Posted by JeffW. on 25 Jun, 2013 03:26 PM

    JeffW.'s Avatar

    Ondina, I got it working now, thanks to your explanation. Sorry you feel dizzy :)

    So for now I simply extend ModelA and ModelB with a BaseModel and they both implement the same interface, which I inject in commands that don't have to know about the concrete classes. That interface was what I was looking for!

    Actually I wasn't aware of how sub-contexting and inheritance works, will look into that later and maybe move some mappings to the shell. Have a good evening!

  14. Support Staff 14 Posted by Ondina D.F. on 25 Jun, 2013 03:31 PM

    Ondina D.F.'s Avatar

    Ah, cool! A nice evening to you, too.:)

  15. JeffW. closed this discussion on 25 Jun, 2013 03:55 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac