简体   繁体   中英

Java inheritance: “Casting” variable in abstract class as static

I'm seeking to reduce redundant code in my Android project. Let me tell you what I already have.

I have two main groups of views. One is called MapView, which is a View containing a bitmap that can be zoomed, panned, etc. The other is called StepInfoView, which is a View that contains static data, such as an array of coordinates and information about those coordinates. This View is also zoomed and panned in an identical way as the MapView is, however, the scale factors and amount panned needs to be independent from the MapView.

StepInfoView is extended by several different classes (6 in total), all of which need to be in sync (coordinates are plotted on one, lines between coordinates are plotted on another, etc.).

So, here is the gist of my code, currently:

public class MapView extends View
{
    protected float scale = 1;

    protected class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
    {
        @Override
        public boolean onScale(ScaleGestureDetector detector)
        {
            scale *= detector.getScaleFactor());
            return true;
        }

    }

    }
... 

public class StepInfoView extends View
{
    static protected float scale = 1;
    protected class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
    {
        @Override
        public boolean onScale(ScaleGestureDetector detector)
        {
            scale *= detector.getScaleFactor());
            return true;
        }

    }
}
...
public class StepView extends StepInfoView
{  
    // Custom onDraw, same scale as PathView
}
public class PathView extends StepInfoView
{
    // Custom onDraw, same scale as StepView
}

As you see, the onScales are identical . I want to create an abstract class to hold the scaling function, let us call it RootView. Both the MapView and StepInfoView have scales, but I cannot make scale static in RootView because the MapView scale must be independent of the StepInfoView. Here is a solution that I know would work, but I don't like the clutter of getters and setters:

abstract class RootView extends View
{
    abstract protected float getScale();

    abstract protected void setScale(float s);
    protected class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
    {
        @Override
        public boolean onScale(ScaleGestureDetector detector)
        {
         setScale(getScale() * detector.getScaleFactor());
         return true;
        }
    }
}
...
public class MapView extends RootView
{
    public float scale = 1;
    protected float getScale(){
        return scale;
    }

    protected void setScale(float s){
        scale = s;
    }
}

public class StepInfoView extends RootView
{
    public static float scale = 1;
    protected float getScale(){
        return scale;
    }

    protected void setScale(float s){
        scale = s;
    }
}
public class StepView extends StepInfoView
{  
    // Custom onDraw, same scale as PathView
}
public class PathView extends StepInfoView
{
    // Custom onDraw, same scale as StepView
}

That works exactly how I want it to work, but once again, there is duplicated identical code (getters and setters and a "scale" variable in MapView and StepInfoView).

What I wish I could do is declare a non-static scale in RootView and "cast" it as static in StepInfoView. That's not exactly possible...

Can ya help me out?

A float costs about 4 bytes. Having another classes will use quite a bit more memory than this. As objects are typically 8 byte aligned, it may not even make the object smaller.

If you want to avoid complexity I would leave the field as non-static.

You could have

class RootView {
    protected final float[] scale;

    RootView() {
        scale = new float[] { 1.0f };
    }

    protected RootView(float[] scale) {
        this.scale = scale;
    }

    public boolean onScale(ScaleGestureDetector detector) {
        scale[0] *= detector.getScaleFactor();
        return true;
    }
}

class StepInfoView extends RootView {
    static final float[] scale = { 1.0f };

    StepInfoView() {
        super(scale);
    }

Why not to move scale field into the RootView class?

update: just got it. I think there is a place for aggregation: make some object container for stepinfo scale value, and pass thru StepInfoView's.

whatever, i think the simplest way it is to use getters.

Move the scale field to the listener, and provide get and set.

In the view, hold a reference to the listener so you can access the scale.

For the MapView, register a different listener for each view instance so they have different scales.

For the StepInfoView, register the same listener for each view instance so they have the same scale. You could store the reference the listener in a static field.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM