8 Replies Latest reply: Mar 3, 2010 7:41 PM by 843853 RSS

    Expanding Objects

    843853
      I am a relatively experienced Java coder, but I am having trouble with this one for some reason...

      Let's say I have 4 Objects. Form, IntField, TextField, DropField
      All the *Field Objects have some similar attributes (let's say idNumber & name)
      And a Form can contain any amount or combinations of these Objects.

      So I started with an Abstract Object GeneralField it contained the name, idNumber variables.
      Then I had
      public class IntField extends GeneralField{...}
      etc.

      My Form Object had a List<GeneralField> and that works well.

      But it became more complex. The *Field types all have different methods. For instance an IntField can have a getMaxInt(); and a DropField has a getIndex();

      But if I have a loop: for(GeneralField gf : list)
      gf can never have access to getMaxInt(); (Obviously).

      So I then add into the mix IField (an Interface which contains all the possible methods)
      and now I have:
      public class IntField extends GeneralField implements IField{}
      and my List<IField>
      But what I now get is IField always has access to getMaxInt() even for a TextField which that makes no sense for. Now I know I could easily just throw an NonsensicalAttributeException or return null, but that doesn't seem appropriate.

      So I started reading more about the Decorator pattern, which I would build an Interface called IIntField and call
      IIntField myInt = new IIntField(new IntField()); 
      and that easily goes into my List<IField>

      but then if I do my loop for(IField f : list) I need some way of knowing that this instance of f is an IIntField. Without resorting toinstanceof.

      I read up on various other patterns and nothing seems to do what I want. The only thing I can think of is to have a boolean on IField that says isIIntField() and when I create a new IIntfield set it to true then I can cast it:
      for(IField f : list){
           if(f.isIIntField()){
           {
                 IIntField i = (IIntField)f;
                ...
           }
      }
      But that is horribly messy and not that extensible.

      I am sure I am missing something super basic, but I just cannot see it yet.

      Can anyone point me in the correct direction?

      I basically need a way of going through List<*Field> and having access to all the various attributes that that particular instance may have.

      Thanks,
      Craig
        • 1. Re: Expanding Objects
          796262
          This might be a dumb suggestion, but why don't you just maintain separate Lists of the different kinds of Objects? You could even have a "master list" that's a List of the other Lists, so you could iterate over all of the Objects when you don't need access to the specialized methods.
          • 2. Re: Expanding Objects
            843853
            This might be a dumb suggestion, but why don't you just maintain separate Lists of the different kinds of Objects?
            That happens to be very good suggestion.

            ~
            • 3. Re: Expanding Objects
              jschellSomeoneStoleMyAlias
              Can anyone point me in the correct direction?
              I didn't see anything in that description that pointed out why you needed lists at all.
              • 4. Re: Expanding Objects
                843853
                cstoss wrote:
                I am sure I am missing something super basic, but I just cannot see it yet.

                Can anyone point me in the correct direction?

                I basically need a way of going through List<*Field> and having access to all the various attributes that that particular instance may have.
                There may not be the one and only "correct" direction, but you definitely should lookup Visitor Pattern / Double Dispatch!
                • 5. Re: Expanding Objects
                  843853
                  Thanks everyone for your responses.

                  I never considered the idea of using separate lists. The problem I see is that I am simplifying the example. There are 20 different "Fields" and about a dozen combinations of attributes to them. So it may get to be a lot to manage. But I will give it a second thought

                  @jschell I need to maintain a series of Objects, what would you recommend besides some form of a List?

                  @Horst_M I used the Visitor pattern in a previous project and had a lot of success with it, I peaked at it for this but couldn't visualize it. I will have another look for sure.


                  Thanks again.
                  • 6. Re: Expanding Objects
                    jschellSomeoneStoleMyAlias
                    cstoss wrote:
                    @jschell I need to maintain a series of Objects, what would you recommend besides some form of a List?
                    Requirements for a list I just created (implementation requirements driven from a business requirement.)
                    - zero or more items
                    - collection passed as method parameter
                    - collection passed via application boundaries

                    From those requirements I arrived at the conclusion that a list is the best way to keep it. And actually a specific type of list as well.
                    You stated that you wanted to keep a disparate bunch of items in a collection but I didn't see any requirements that drove to that need.
                    • 7. Re: Expanding Objects
                      843853
                      cstoss wrote:
                      @Horst_M I used the Visitor pattern in a previous project and had a lot of success with it, I peaked at it for this but couldn't visualize it. I will have another look for sure.
                      Looking at your code example the visitor pattern cries out loud "visit me".

                      Original code:
                      for(IField f : list){
                           if(f.isIIntField()){
                           {
                                 IIntField i = (IIntField)f;
                                ...
                           }
                      }
                      will be changed to:
                      ConcreteVisitorA implements IVisitor
                      ....
                      for(IField f : list){
                         f.accept(this);
                      }
                      ...
                      public void visitIntField(IIntField i) {
                      ...
                      }
                      And IIntField will be extended with:
                      public void accept(IVisitor v) {
                        v.visitIntField(this);
                      }
                      • 8. Re: Expanding Objects
                        843853
                        Maybe this although I'm not a big fan of such Generic usage:
                        public <F extends GenericField> F[] getFields(Class<F> type) {
                        List<F> temp = new LinkedList<F>();
                        for(F f:fields) {
                          if(type.isAssignableFrom(f.getClass)) {
                            temp.add(f);
                          }
                        }
                        F[] array = (F[])Arrays.newInstance(type, temp.size());
                        temp.toArray(array);
                        return array;
                        }
                        You might need minor change to get through compile if I made any mistake. But I'm sure this work because I used it before. So you could just call getFields(TextField.class) to get all your text fields. It also works for all other types.