Solved

Design Question: Using Members To Share Data Between A Method and SubMethod?

Posted on 2010-09-02
21
284 Views
Last Modified: 2012-05-10
Say we have a public method "method," which uses private "subMethod1" and private "subMethod2" in its calculation.  These subMethods serve no other purpose than to break down "method" into more readable, encapsulated sub-parts.  

We need each of these sub methods to operate on 2 or more primitive data types, which are local variables defined at the top of method.  We cannot pass them into the sub methods by reference, since java does not allow primitives to be passed by reference, and anyway passing an argument in to be altered is not a preferred design idiom.  

So our solution is to refactor, and change the local variables defined at the top of method to member variables, which can of course be read and written by both method and its sub-methods.  The problem (maybe it is a problem) is that now we have member variables that don't really exist to store object state, but only exist, effectively, during the execution of method.  Of course, in actuality they exist throughout the whole lifetime of the object, but they are only ever used during the execution of method, and they could vanish at other times without affecting the behavior of the object at all (keep in mind that method initializes the members to default values at the beginning of its method body).  

So something about that design feels wrong.  Is it?  If so, what is a better way to refactor?

Thanks,
Jonah
0
Comment
Question by:Jonah11
  • 9
  • 6
  • 3
  • +2
21 Comments
 
LVL 16

Assisted Solution

by:Valeri
Valeri earned 250 total points
ID: 33584672
Keep as a member variables only the variables that concerns the object state!
All of the other variables, needed for the calculations in "Method" should be local for this method. and if you want after completing of the subMethods the changed values(of the primitive types)  to be "visible" to "Method" you have to pass them through some Object, which will be removed from the Garbage collector after completing of the "Method".
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33584720
So you can pass the primitive valiables to the subMethods "by reference". Just collect them into the Object (at the top of the Method) and pass the object to the subMethods.
0
 
LVL 7

Author Comment

by:Jonah11
ID: 33584721
Valeri,

This solution is not an option.  My method is used as part of a simulation (it will be run millions of times in a loop), and the creation of Objects as wrappers merely to pass the primitives back and forth will have too large of a performance hit.
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33584829
Then create only one instance of such as Object, make it member variable of your Main Object and before calculations just reinitialize the variables in this Object which will be responsible for the calculations! And to make things more clear I think that will be good to move submethods to this Object, because they are used only for the calculations.
0
 
LVL 7

Author Comment

by:Jonah11
ID: 33584869
Are you suggesting I create an inner class to encapsulate the sub methods and the shared primitive data?  
0
 
LVL 7

Author Comment

by:Jonah11
ID: 33584932
Actually, it seems that you are not, so I don't see how your solution avoid the problem that mine does.  The member Object wrapping the primitives still serves no purpose other than sharing info between method and its sub-methods.  That is, the member object you propose is still not existing to save state for the main object, as you enthusiastically say it should: "Keep as a member variables only the variables that concerns the object state!"
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33584962
Yes, something like that. But if you create it as a inner class whenever you instantiate the Main class, the inner class will be also instantiated. It shoud be static inner class. And it can be just different class and to be static in your MainClass in order to have only one instance of it.
Of course you have to be very careful with the static variables :-)
Also if your app is multithreading one you have to redesign using of this class. Then it shouldn't be static, but you have to have different instance of it per each one of the threads, because performance is very omportant.
0
 
LVL 7

Author Comment

by:Jonah11
ID: 33585014
I really don't see how creating a static inner class is answering the design problem I had in the OP, and the one that you shared when you said "Keep as a member variables only the variables that concerns the object state!"  Now we will just have a static inner class which exists merely to share information between methods of the parent class.  Why is that any better than having member variables for the same purpose?
0
 
LVL 7

Author Comment

by:Jonah11
ID: 33585042
Or would both method and its submethods (and the primitive data) all be static methods of the static inner class?  Then the public method of the parent class would just delegate to its static counterpart in the inner class?  I think that might work.....
0
 
LVL 26

Expert Comment

by:ksivananth
ID: 33585295
>>My method is used as part of a simulation (it will be run millions of times in a loop), and the creation of Objects as wrappers merely to pass the primitives back and forth will have too large of a performance hit.
>>

can you try it really and then compare the performance hit? actually wrapping into an class is the nice follow of oops. what you think is the optimized code may not be optimized code for the compiler, the recommondation is write simple neat oops code and the compiler will optimize it for you!
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 10

Expert Comment

by:Hegemon
ID: 33585584
- .. and the creation of Objects as wrappers merely to pass the primitives back and forth will have too large of a performance hit.

You can create this object only once and invoke its setters each time you need to return the data.
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33585640
to Jonah11@33585042 : Yes, exactly
to ksivananth : It's very interesting! But I think that the compiler will not avoid instantiating of new Object again and again... and this will slow down the application?!?!
0
 
LVL 7

Author Comment

by:Jonah11
ID: 33592820
can you try it really and then compare the performance hit? actually  wrapping into an class is the nice follow of oops. what you think is the  optimized code may not be optimized code for the compiler, the  recommondation is write simple neat oops code and the compiler will  optimize it for you!

ksivananth:

too bad reality is not this simple.  I've attached a very simple (and silly) example that demonstrates the performance.  In this simple example using the pass by reference method with a wrapping object increases execution time by more than 50%.  


package scratch;


public class TestSharedMembers {
    
    protected int m17Multiples;
    protected int m23Multiples;
    
    public int methodPrimitive(int i) {
        
        m17Multiples = 0;
        m23Multiples = 0;
        
        calc17Primitive(i);
        calc23Primitive(i);
        
        return m17Multiples + m23Multiples;
    }
    
    private void calc17Primitive(int i) {
        if (i % 17 == 0) 
            m17Multiples++;
    }
    private void calc23Primitive(int i) {
        if (i % 23 == 0) 
            m23Multiples++;
    }
    
    
    class IntWrapper {
        private int mInt;
        public IntWrapper(int i) {
            mInt = i;
        }
        public int getInt() {
            return mInt;
        }
        public void increment() {
            mInt++;
        }
    }
    public int methodObject(int i) {
        
        IntWrapper o17 = new IntWrapper(0);
        IntWrapper o23 = new IntWrapper(0);
        
        calc17Object(i, o17);
        calc23Object(i, o23);
        
        return o17.getInt() + o23.getInt();
    }
    
    private void calc17Object(int i, IntWrapper o) {
        if (i % 17 == 0) 
            o.increment();
    }
    private void calc23Object(int i, IntWrapper o) {
        if (i % 23 == 0) 
            o.increment();
    }
    
    
    public static void main(String[] args) {
        TestSharedMembers t = new TestSharedMembers();
        final int NUM_ITERS = 20000000;
        
        double start = System.currentTimeMillis();
        int total = 0;
        for (int i=0; i<NUM_ITERS; i++) {
            total += t.methodPrimitive(i);
        }
        double stop = System.currentTimeMillis();
        System.out.println(total);
        System.out.println(stop - start);
        
        start = System.currentTimeMillis();
        total = 0;
        for (int i=0; i<NUM_ITERS; i++) {
            total += t.methodObject(i);
        }
        stop = System.currentTimeMillis();
        System.out.println(total);
        System.out.println(stop - start);
        
    }
}

Open in new window

0
 
LVL 7

Author Comment

by:Jonah11
ID: 33593033
Valeri,

I have been thinking about your solution some more, and I don't think a static inner class will work.  The problem is that method and sub-methods in question would need access to non-static members of the parent class.  

An instance class might work, in which case we could create an inner class called "MethodHelper" or something like that, which would exist only to house the implementation of method.

What do you think of that?
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33594270
>>
I have been thinking about your solution some more, and I don't think a static inner class will work.  The problem is that method and sub-methods in question would need access to non-static members of the parent class.
>>
Yes, you are right! I didn't consider that.
>> An instance class might work...
Yes, I think so. If you define your non-static members of the parent class as protected you can access them directly in your instance class.
But it will not work in multithreading environment. Is your app multithreading one?
0
 
LVL 7

Author Comment

by:Jonah11
ID: 33596387
No, it won't be multithreaded.
0
 
LVL 26

Accepted Solution

by:
ksivananth earned 250 total points
ID: 33609440
>>I've attached a very simple (and silly)

actually, it's a silly example! as per your requirement, see below

>>We need each of these sub methods to operate on 2 or more primitive data types

so the test case should serve the purpose, i.e., dealing with 2 or more arguments! The reality is, when you try to solve a complex problem and don't follow oops, the code will be cluttered and complex which may actually degrade the performance. btw check the example I have added, neglegible performance diff but on the other hand you get easy to maintain( flexible to extend functionality ) neat OOPs code.

public class TestSharedMembers {
   
    protected int m17Multiples;
    protected int m23Multiples;
   
    public int methodPrimitive(int i) {
       
        m17Multiples = 0;
        m23Multiples = 0;
       
        calc17Primitive(i);
        calc23Primitive(i);
       
        return m17Multiples + m23Multiples;
    }
   
    private void calc17Primitive(int i) {
        if (i % 17 == 0)
            m17Multiples++;
    }
    private void calc23Primitive(int i) {
        if (i % 23 == 0)
            m23Multiples++;
    }
   
   
    static class IntWrapper {
        protected int mInt;
       
        public IntWrapper(int i) {
            mInt = i;
        }
        public int getInt() {
            return mInt;
        }
        public void increment() {
            mInt++;
        }
    }

    static class IntWrapperOverriden{
          private int index ;
          private int i17 ;
          private int i23 ;
       
        public IntWrapperOverriden(){

        }
       
        public void reset(){
              i17 = 0 ;
              i23 = 0 ;
        }

            public int getIndex(){
                  return index;
            }

            public void setIndex( int index ){
                  this.index = index;
            }

            public int getI17(){
                  return i17;
            }

            public int getI23(){
                  return i23;
            }

        public void increment17() {
              i17++;
        }

        public void increment23() {
              i23++;
        }
    }

    public int methodObject(int i) {
       
        IntWrapper o17 = new IntWrapper(0);
        IntWrapper o23 = new IntWrapper(0);
       
        calc17Object(i, o17);
        calc23Object(i, o23);
       
        return o17.getInt() + o23.getInt();
    }
   
    public int methodObject( IntWrapperOverriden iwo ) {
        calc17Object( iwo );
        calc23Object( iwo );
       
        return iwo.getI17() + iwo.getI23() ;
    }
   
    private void calc17Object(IntWrapperOverriden iwo) {
        if (iwo.getIndex() % 17 == 0)
            iwo.increment17();
    }
   
    private void calc23Object(IntWrapperOverriden iwo) {
        if (iwo.getIndex() % 23 == 0)
              iwo.increment23();
    }
   
    private void calc17Object(int i, IntWrapper o) {
        if (i % 17 == 0)
            o.increment();
    }
    private void calc23Object(int i, IntWrapper o) {
        if (i % 23 == 0)
            o.increment();
    }
   
    private void testNew(){
        final int NUM_ITERS = 20000000;
        long start = System.currentTimeMillis();
        int total = 0;
        IntWrapperOverriden iwo = new IntWrapperOverriden() ;
        for (int i=0; i<NUM_ITERS; i++) {
              iwo.setIndex( i ) ;
            total += methodObject( iwo );
            iwo.reset() ;
        }
        long stop = System.currentTimeMillis();
        System.out.println(total);
        System.out.println(stop - start);
    }
   
    public static void main(String[] args) {
        TestSharedMembers t = new TestSharedMembers();
        final int NUM_ITERS = 20000000;
       
        t.testNew() ;
       
        double start = System.currentTimeMillis();
        int total = 0;
        for (int i=0; i<NUM_ITERS; i++) {
            total += t.methodPrimitive(i);
        }
        double stop = System.currentTimeMillis();
        System.out.println(total);
        System.out.println(stop - start);
       
        start = System.currentTimeMillis();
        total = 0;
        for (int i=0; i<NUM_ITERS; i++) {
            total += t.methodObject(i);
        }
        stop = System.currentTimeMillis();
        System.out.println(total);
        System.out.println(stop - start);
    }
}
0
 
LVL 26

Expert Comment

by:ksivananth
ID: 33609481
0
 
LVL 7

Author Comment

by:Jonah11
ID: 33612809
ksivananth:

I understand the importance of good OO design -- that is why I made this post.  There is no need to make that case to me.   I just happened to be facing a conflict here between good design and good performance.  I do appreciate your input though -- I think I can use your ideas above to get both things.

I just need to experiment a bit more to make sure I don't have any further questions.

Thanks for your help.
0
 
LVL 26

Expert Comment

by:mrcoffee365
ID: 37136733
This question has been classified as abandoned and is closed as part of the Cleanup Program. See the recommendation for more details.
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now