Jump to content

Using interfaces with abstract classes


NotionCommotion

Recommended Posts

Before learning about interfaces, I would often use abstract classes:

abstract class MyAbstractClass
{
    abstract public function someMethodToOverride();

    public function availableMethod()
    {
        //code common to all extender classes which does not need to be duplicated...
    }
}

class MyFirstClass extends MyAbstractClass
{
    public function someMethodToOverride()
    {
        //code unique to each extending class...
    }
}

class MySecondClass extends MyAbstractClass
{
    public function someMethodToOverride()
    {
        //code unique to each extending class...
    }
}

Now trying to more often use interfaces.  It is my understanding that the interface is primarily a guide to the user of the class, while abstract classes are to help the classes author create the class.

 

Does it make sense to use both at the same time? For the above, does it make more sense to add someMethodToOverride() and availableMethod() to MyAbstractClass's interface?  Or maybe get rid of MyAbstractClass's abstract method someMethodToOverride(), and just but this method in MyFirstClass's interface?

Link to comment
Share on other sites

It is my understanding that the interface is primarily a guide to the user of the class, while abstract classes are to help the classes author create the class.

Sounds right to me.

 

Does it make sense to use both at the same time?

It's not one question about whether you should use both. It's two questions: one about using interfaces and one about using abstract classes.

 

Interface: Does a class try to promise a certain behavior? Could that behavior exist with another class not in this hierarchy? Is the behavior a secondary aspect to the original class? Does the behavior have a more "can do X" attitude rather than "is a Y"?

Abstract: Are you planning to (or at least leaving the door open to) subclass this class? Will there be some amount of code that's probably going to be needed by all subclasses, or at least most of them, but some portion that is not known yet?

Edited by requinix
*to
Link to comment
Share on other sites

Interface: Does a class try promise a certain behavior?

"try promise"?  Normally, I would assume this is a typo, but not going to assume anything on this topic.

 

Is the behavior a secondary aspect to the original class? Does the behavior have a more "can do X" attitude rather than "is a Y"?

"behavior"?  As in methods?  "can do X" as in can do arithmetic rather than "is a Y" as in is a calculator?

 

Abstract: Are you planning to (or at least leaving the door open to) subclass this class? Will there be some amount of code that's probably going to be needed by all subclasses, or at least most of them, but some portion that is not known yet?

For me, this seems to be the norm and not the exception.  Shouldn't we always attempt to centralize script instead of duplicating it?  I've heard others voice that abstract classes should rarely be used and am questioning whether I am using them too often.

Link to comment
Share on other sites

"try promise"?  Normally, I would assume this is a typo, but not going to assume anything on this topic.

I tend to revise my posts a few times before posting. Occasionally words get lost. Words such as "to".

 

"behavior"?  As in methods?  "can do X" as in can do arithmetic rather than "is a Y" as in is a calculator?

A calculator has calculator-like behavior, such as "put the current value into temporary memory" or "calculate the result of this expression". A class can be a calculator, and an interface can say that a class behaves like a calculator.

interface ISaveRestoreState {

	public function saveState(): string;

	public function restoreState(string $state);

}

interface IEvaluateExpression {

	public function evaluate(string $expr);

}

interface ICalculator extends
	ISaveRestoreState,
	IEvaluateExpression
{
}

class MobileCalculatorApp implements ICalculator { ... }
class DesktopCalculatorApp implements ICalculator { ... }

For me, this seems to be the norm and not the exception.

Which "this"?

 

Shouldn't we always attempt to centralize script instead of duplicating it?  I've heard others voice that abstract classes should rarely be used and am questioning whether I am using them too often.

If you find yourself wanting to copy code from one class into a new sibling you're writing then it's easy to pull code out of the one class and into an abstract parent instead, so there's no need to do it ahead of time "just in case". So if you feel better about it, don't use an abstract class until you need it.

 

My experiences may be a bit atypical as I tend to write lower-level code than the average PHP developer. More often than not I will build something from the ground up than from the bottom down, and I have no problem adding an extra class or two because I anticipate a need for them later. Like right now, in my own code I have basically

// rendering a thing is a behavior that isn't confined to a particular type of object
interface IRenderable {

	public function render();

	public function renderToString();

}

// view is a renderable thing
abstract class View implements IRenderable {

	// likely the method that will be implemented by a child
	public abstract function render();

	// I can implement this here so the child doesn't have to
	public function renderToString() {
		ob_start();
		$this->render();
		return ob_get_clean();
	}

}

class StaticFileView extends View {

	// ...

	// required implementation
	public function render() {
		readfile($this->file);
	}

	// I could use View::renderToString, however I can do it more efficiently myself
	public function renderToString() {
		return file_get_contents($this->file);
	}

}
The whole point of the abstract View is so that child classes don't have to implement renderToString by themselves, even though some may want to. It's a matter of practicality and code reuse. For the most part if code needs to deal with rendering a thing then it will work with the IRenderable interface.

 

 

Don't worry so much about all this. You're asking questions that are best answered with experience and that can't always be expressed in words. Do something for a while and think about how it worked out; if you decide it was really bad then you can go back and refactor, but if it really was that bad then you would probably have realized sooner so it's not actually as bad as you think.

Edited by requinix
Link to comment
Share on other sites

I've heard others voice that abstract classes should rarely be used and am questioning whether I am using them too often.

 

If you need the particular features offered by an abstract class, use an abstract class. This is perfectly fine. The point is that the main tools in OOP are still interfaces and concrete classes. When programmers use abstract classes a lot, that can indicate the hammer syndrome (“When all you have is a hammer, everything looks like a nail.”). Remember when you used lambdas for almost every task and came up with strange solutions to simple problems? That's what I mean.

 

Abstract classes are just one option. Sometimes a concrete base class works just as well. Sometimes a Trait is more useful. And sometimes it makes sense to just duplicate the code. Building complex class hierarchies and writing dozens of lines of OOP boilerplate code only to reuse a few lines of functional code is obviously not very clever.

 

So this is neither about avoiding abstract classes nor about desparately trying to find ways to put them into your code. It's about knowing the whole spectrum of tools.

Edited by Jacques1
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.