Inheritance and base functionality


  • 🚽 Regular

    I'm trying to make a simple MVP framework for my Android work. I'm having to annotate with @CallSuper to ensure children implementing override-able methods don't disturb the base functionality. Does this example look OK or is there a better way to accomplish this?

    Edit: I suppose I could make start() and stop() final and then have them call private onStart() and onStop() methods for the children maybe? Nope, private methods are not inherited, so then I have an encapsulation problem :/

    public interface BasePresenter {
        void invalidateView();
        void detachView();
        void start();
        void stop();
    }
    
    public abstract class MvpPresenter implements BasePresenter {
        public boolean isPresenterStopped = true;
    
        //region Methods that must be implemented by Children.
    
        public abstract void invalidateView();
        public abstract void detachView();
    
        //endregion
    
        //region Methods that can be implemented by Children.
    
        @CallSuper
        public void start() {
            isPresenterStopped = false;
        }
    
        @CallSuper
        public void stop() {
            isPresenterStopped = true;
        }
    
        //endregion
    }
    

  • 🚽 Regular

    @thegoryone said in Inheritance and base functionality:

    @cursorkeys said in Inheritance and base functionality:

    Nope, private methods are not inherited

    ...that's how encapsulation and inheritance work. Not to sound like a complete arsehole (Which I probably do), but if you don't understand how inheritance and encapsulation work, you might need to do a bit more reading first because this is going to get very messy for you.

    And this is one of the basics of OO programming.

    Not at all, that's very fair. It looked wrong so I just wanted confirmation I was doing it wrong. I'll go do some reading, OOP is an area I'm very poor on.

    (My incorrect thinking was as it was an abstract class they might be)



  • This looks OK to me, the non-Java non-Android programmer who rarely even uses OOP these days anymore.


  • 🚽 Regular

    I did some reading, making the superclass start()/stop() methods final and then having protected onStart()/onStop() methods for the children gives me the functionality and visibility I want. I don't need @CallSuper any more and I think it looks much better.
    I will keep reading tutorials until it all sinks in properly!

    public interface BasePresenter {
        void invalidateView();
        void detachView();
        void start();
        void stop();
    }
    
    public abstract class MvpPresenter implements BasePresenter {
        public boolean isPresenterStopped = true;
    
        public abstract void invalidateView();
        public abstract void detachView();
    
        public final void start() {
            isPresenterStopped = false;
            onStart();
        }
    
        public final void stop() {
            isPresenterStopped = true;
            onStop();
        }
    
        protected void onStart() {
        }
    
        protected void onStop() {
        }
    }
    


  • @cursorkeys said in Inheritance and base functionality:

    I did some reading, making the superclass start()/stop() methods final and then having protected onStart()/onStop() methods for the children gives me the functionality and visibility I want. I don't need @CallSuper any more and I think it looks much better.
    I will keep reading tutorials until it all sinks in properly!

    Nice.



  • @cursorkeys Maybe I didn't read carefully enough, but if all you need is to call a parent class's method from the override, why not just use super.method(...)?


  • 🚽 Regular

    @dragnslcr said in Inheritance and base functionality:

    @cursorkeys Maybe I didn't read carefully enough, but if all you need is to call a parent class's method from the override, why not just use super.method(...)?

    That was the problem as I saw it. The child would have to call super., things would break if they didn't. I can enforce that in Android with a @CallSuper annotation so they get a compile-time error if they don't, but it seemed inelegant.

    I think this is better because things calling the subclasses can now only see the superclass start() and stop() and the subclass gets it's own onStart() and onStop() to override if it needs to extend anything (and anything other than the subclass can't call those by mistake).


  • Discourse touched me in a no-no place

    @cursorkeys said in Inheritance and base functionality:

    I did some reading, making the superclass start()/stop() methods final and then having protected onStart()/onStop() methods for the children gives me the functionality and visibility I want.

    This is related to the Open/Closed Principle, and is something that I've seen some style-checkers enforce.



  • 👍

    Next step: Dependency Injection 👀



  • @jazzyjosh said in Inheritance and base functionality:

    Next step: Dependency Injection

    Of all the OOP cruft that came out of the 90-ies and 2000-s, that's the most useful pattern IMO.


  • 🚽 Regular

    @jazzyjosh said in Inheritance and base functionality:

    👍

    Next step: Dependency Injection 👀

    I'm not using Dagger or anything like that but the subclass constructors accept the Activity and View, I don't know if that counts?

    public class ExamplePresenter extends MvpPresenter implements ExampleContract.Presenter {
    
        //We hold a weak reference to the View to ensure we do not capture it past the normal Android Lifecycle.
        private WeakReference<ExampleContract.View> mWeakView;
        private ExampleActivity mActivity;
    
        public ExamplePresenter(@NonNull ExampleActivity activity, @NonNull ExampleContract.View view) {
            checkNotNull(view, "view cannot be null!");
    
            mWeakView = new WeakReference<>(view);
    
            ExampleContract.View weakView = mWeakView.get();
            weakView.attachPresenter(this);
    
            mActivity = checkNotNull(activity, "Activity cannot be null!");
        }
    

    ExampleContract.View weakView = mWeakView.get(); was the main reason I was complaining about Java not having type inference. I have a lot of this bit of code in the Presenters and it's a shame you can't write var weakView = mWeakView.get();



  • @cursorkeys C# has syntax for that. Not hacky annotation syntax, either



  • Why not just accept a WeakReference<ExampleContract.View>?

    Not sure why having to specify the type is a big deal though.

    But yeah, you've got the pattern. You would just integrate a framework, annotate with @Inject and replace calls to new with constructor arguments. Plus you'd get rid of the @NonNull annotations and checks because your injector would fail to initialize if it couldn't resolve a way to make a concrete implementation.


  • 🚽 Regular

    @jazzyjosh said in Inheritance and base functionality:

    Why not just accept a WeakReference<ExampleContract.View>?

    Good idea, I've changed it. It originally was a normal View, then I realized why the lifecycle was getting stuffed up and jammed a WeakReference in there without changing the constructor for some reason.

    @jazzyjosh said in Inheritance and base functionality:

    Not sure why having to specify the type is a big deal though.

    Mostly laziness when cut and pasting. It does make code look neater when there's just a var and not a long(er) type there too.


  • Impossible Mission - B

    @cartman82 said in Inheritance and base functionality:

    @jazzyjosh said in Inheritance and base functionality:

    Next step: Dependency Injection

    Of all the OOP cruft that came out of the 90-ies and 2000-s, that's the most useful pattern IMO.

    🤢

    90% of Dependency Injection is just a hacky Java solution to a bad Java architectural problem. (Which, unfortunately, the CLR guys copied.) Proper metaclasses would eliminate or massively reduce most cases where DI is needed.



  • @masonwheeler said in Inheritance and base functionality:

    90% of Dependency Injection is just a hacky Java solution to a bad Java architectural problem. (Which, unfortunately, the CLR guys copied.) Proper metaclasses would eliminate or massively reduce most cases where DI is needed.

    No. DI (or IoC in general) is much more useful than some JAVA thing. I am using it in places that have nothing to do with Java or OOP in general.



  • @cursorkeys said in Inheritance and base functionality:

    @jazzyjosh said in Inheritance and base functionality:

    👍

    Next step: Dependency Injection 👀

    I'm not using Dagger or anything like that but the subclass constructors accept the Activity and View, I don't know if that counts?

    public class ExamplePresenter extends MvpPresenter implements ExampleContract.Presenter {
    
        //We hold a weak reference to the View to ensure we do not capture it past the normal Android Lifecycle.
        private WeakReference<ExampleContract.View> mWeakView;
        private ExampleActivity mActivity;
    
        public ExamplePresenter(@NonNull ExampleActivity activity, @NonNull ExampleContract.View view) {
            checkNotNull(view, "view cannot be null!");
    
            mWeakView = new WeakReference<>(view);
    
            ExampleContract.View weakView = mWeakView.get();
            weakView.attachPresenter(this);
    
            mActivity = checkNotNull(activity, "Activity cannot be null!");
        }
    

    ExampleContract.View weakView = mWeakView.get(); was the main reason I was complaining about Java not having type inference. I have a lot of this bit of code in the Presenters and it's a shame you can't write var weakView = mWeakView.get();

    Why not just use view? Inside that function, weakView is going to be identical to view anyway.


  • 🚽 Regular

    @ben_lubar said in Inheritance and base functionality:

    @cursorkeys said in Inheritance and base functionality:

    @jazzyjosh said in Inheritance and base functionality:

    👍

    Next step: Dependency Injection 👀

    I'm not using Dagger or anything like that but the subclass constructors accept the Activity and View, I don't know if that counts?

    public class ExamplePresenter extends MvpPresenter implements ExampleContract.Presenter {
    
        //We hold a weak reference to the View to ensure we do not capture it past the normal Android Lifecycle.
        private WeakReference<ExampleContract.View> mWeakView;
        private ExampleActivity mActivity;
    
        public ExamplePresenter(@NonNull ExampleActivity activity, @NonNull ExampleContract.View view) {
            checkNotNull(view, "view cannot be null!");
    
            mWeakView = new WeakReference<>(view);
    
            ExampleContract.View weakView = mWeakView.get();
            weakView.attachPresenter(this);
    
            mActivity = checkNotNull(activity, "Activity cannot be null!");
        }
    

    ExampleContract.View weakView = mWeakView.get(); was the main reason I was complaining about Java not having type inference. I have a lot of this bit of code in the Presenters and it's a shame you can't write var weakView = mWeakView.get();

    Why not just use view? Inside that function, weakView is going to be identical to view anyway.

    Inside that particular function there was no good reason, it was an artefact of originally just having a View and then realising there was a problem and changing the class member variable to a WeakReference and stuffing it in to that constructor.
    After @JazzyJosh pointed it out I've refactored that properly.



  • @cartman82 said in Inheritance and base functionality:

    Of all the OOP cruft that came out of the 90-ies and 2000-s, that's the most useful pattern IMO.

    Please do not confuse Dependency Inversion (the principle which was formalized in that time frame) with the specific technique of Dependency Injection (what most tools do).

    The former is valuable in the vast majority of cases [nothing is ever 100%], the latter can often be problematic and be much more complex than a simple implementation which achieves the principle.



  • @thecpuwizard said in Inheritance and base functionality:

    Please do not confuse Dependency Inversion (the principle which was formalized in that time frame) with the specific technique of Dependency Injection (what most tools do).
    The former is valuable in the vast majority of cases [nothing is ever 100%], the latter can often be problematic and be much more complex than a simple implementation which achieves the principle.

    I get that. IoC and DI are colloquially often treated as synonyms, so I used the term in that manner.

    My javascript app is certainly not going to use the same IoC mechanism as an app written in a fully OOP language.



  • @cartman82 Mine does

    Granted it is written in Java ;)



  • @cartman82 - Pretty sure you "Get it", so I am posting for other readers...

    Without DIP [Inversion], a piece of code needs some other resource, it creates it [typically calling "new xxxx(...)" in most languages)..
    With DIP, in the same situation the determine of what to create is somewhere (anywhere) outside the class instance needing the resource.

    DI [Injection] uses either the constructor parameters or properties to pass the instances....

    However replacing the "new X(.....)" with "Something::GiveMeAnX(....)" is a minimal (completely valid) DIP



  • Yay functors! The "colloquial" equivalence between IoC and DI is the basis of functor-based reasoning.



  • @thecpuwizard said in Inheritance and base functionality:

    However replacing the "new X(.....)" with "Something::GiveMeAnX(....)" is a minimal (completely valid) DIP

    Oh, so you like the ServiceLocator pattern. The one thing more toxic and cancerous than languages that start with JAVA.

    You may think I feel strongly about this. Why shouldn't I?

    Hidden dependencies are a plague that should be burned out at every opportunity. You cannot write testable software if you use that filth.


Log in to reply