Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protected abstract or public abstract method in abstract class

Hi I have an abstract class in which I have some public methods and some abstract ones. I have the public so that they implement the common methods for the derived classes.

What is confusing me is why I will want to define a public abstract method instead of protected abstract. That makes no sense to me to define a public abstract method in abstract class.... because if is an abstract will be overridden, in the derived classes, but the same is if is defined as public but somehow it makes more sense to define it as protected as we know that we will override that in the derived classes.

Is it wrong to define the method as public abstract in an abstract class? Which is better and why?

like image 785
Lyubomir Velchev Avatar asked May 21 '15 08:05

Lyubomir Velchev


People also ask

Can abstract class have public abstract methods?

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation. However, with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods.

Is abstract method private or public?

You cannot have a private abstract method because subclasses can't see private members of a superclass.

Can abstract class have protected fields?

You will be hard pressed to find Abstract classes that have protected fields (let alone any fields). That being said there are always exceptions and you are not always writing library code (ie public api).


4 Answers

It depends on what you want to achieve. For example, you have a Television class that has 3 methods, TurnOn, TurnOff, and Draw.

You only want clients to TurnOn or TurnOff the TV but only its subclass should know what and how to Draw on the screen. So, Television will look more or less like below.

public abstract class Television
{
    public abstract void TurnOn();

    public abstract void TurnOff();

    protected abstract void Draw();
}

Then each company has its own implementation.

public sealed class MyTelevision
    : Television
{
    public override void TurnOn()
    {
        Console.WriteLine("Turn on my tv");
    }

    public override void TurnOff()
    {
        Console.WriteLine("Turn off my tv");
    }

    protected override void Draw()
    {
        // code here.
    }
}

Clients can TurnOn or TurnOff a TV but cannot Draw anything on the screen.

like image 60
Ekk Avatar answered Oct 17 '22 00:10

Ekk


For the same reason you want a public method in an object :) You just don't know the particular implementation at this stage. It is common in classes with very high level of abstraction, middlewares for example.

Edit: It is 100% legal. You just need to be sure that it is functionality that you want to expose to the rest of the world in every concrete implementation. Entry point methods (ex: start, execute, parse..) are usually of this kind.

UML Examlple of abstract public

like image 41
Sam Aleksov Avatar answered Oct 16 '22 23:10

Sam Aleksov


The Abstract Class itself has to be as accessible as the Classes, which inherit from it. So if the inherited Classes are Public, the Abstract Class has to be public too.

Public Abstract has the same Idea like other Public Methods: If you have a Abstract Class, you will pass this arround. So if this Method should get called from outside, it's public. If the method is just for communication between Child and Parent, protected is the way to go. Easy example, see the Main-Method as the user of the abstract class:

    static void Main(string[] args)
    {
        Animal cat = new Cat();
        Animal dog = new Dog();

        cat.Eat();
        dog.Eat();

        cat.Move();
        dog.Move();
    }


    public abstract class Animal
    {
        public abstract void Eat();
        protected abstract void ComplexMoving();

        public void Move()
        {
            ComplexMoving();
        }

    }

    public class Dog : Animal
    {
        public override void Eat()
        {
            Debug.WriteLine("Dog says Namnam");
        }

        protected override void ComplexMoving()
        {
            Debug.WriteLine("Dog no stupid");
        }
    }

    public class Cat: Animal
    {
        public override void Eat()
        {
            Debug.WriteLine("Cat says namnam");
        }

        protected override void ComplexMoving()
        {
            Debug.WriteLine("Cat does a slalom");
        }
    }
like image 41
Matthias Müller Avatar answered Oct 17 '22 00:10

Matthias Müller


TLTR: because of Open-Close principle.

Why it makes sense to have abstract members protected instead of public is, from what I can see, to hide "implementation details". It is convenient to expose one single "entry point" if you want to ensure that the intent of which each abstract member is defined inside the class is preserved. Normally, it is the public method which will orchestrate when and what abstract members are called or accessed and in what particular order and under what circumstances, but the tradeoff for this layer of encapsulation is that you lose the extensibility property.

Explanation:

Suppose we create a library with multiple exception handler classes.

Initial implementation:

namespace MyLibrary;

public abstract class ExceptionHandlerBase
{
    protected abstract void HandleException(Exception ex, Action operation);

    public void Execute(Action operation)
    {
        try {
            operation.Invoke();
        } catch(Exception ex) {
            this.HandleException(ex, operation);
        }
    }
}

public class InputExceptionHandler: ExceptionHandlerBase
{
    protected override void HandleException(Exception ex, Action operation)
    {
        throw new Exception(
            message: "Wrong input"   // or whatever...
            inner: ex);
    }
}

public class DbExceptionHandler : ExceptionHandlerBase
{
    protected override void HandleException(Exception ex, Action operation)
    {
        Console.WriteLine("Failed to connect to database. Retrying...");
        operation.Invoke();
    }
}

Now, if we want to extend the behavior of ExceptionHandlerBase we will see that we are limited because of that protected access modifier of ExceptionHandlerBase.HandleException method.

Let's try to add a hook before ExceptionHandlerBase.HandleException method:

class ExceptionHandlerWrapper : ExceptionHandlerBase
{
    readonly ExceptionHandlerBase _base;

    public ExceptionHandlerWrapper(ExceptionHandlerBase @base)
    {
        thos._base = @base;
    }

    protected override void HandleException(Exception ex, Action operation)
    {
        this.BeforeHandleException();
        this._base.HandleException(ex, operation); // Compile error**
    }
    
    private void BeforeHandleException()
    {
        // do additional stuff
    }
}

As you can see, there is a compilation error because ExceptionHandlerBase.HandleException is not accessible from outside the class that defines it.

like image 24
Darius Avatar answered Oct 17 '22 00:10

Darius