Jump to content

OOP - Abstract Classes


benanamen

Recommended Posts

I read the manual and numerous other resources on Abstract classes. Abstract classes appear to be very similar to Interface classes.
  1. When should I use an Abstract Class instead of an Interface Class?
     
  2. Should ALL classes that are not implementing an interface be programmed against an Abstract Class? If not, what decides that a class should not be derived from an Abstract Class nor an Interface Class?
Link to comment
Share on other sites

"Abstract" is an adjective. "Class" is a noun. "Interface" is a noun. An "abstract class" is a type of class. An "interface class" is nonsense.

 

Abstract classes and interfaces have similar purposes, yes, but there's one big difference: whether you can put code in it. Use an interface if you want a class to look a certain way but don't care how it actually goes about doing that. The power of an abstract class comes when you want more than one class to look a certain way, they'll all behave a little differently from each other, but you know there will be some code that works the same in all of them and don't want to have to repeat it everywhere.

// I don't care how these classes work, but they need do specific methods in them
interface IBinaryMathOperator {

	public function __construct($a, $b);

	public function getOperandA();
	public function getOperandB();

	public function operate();

}

// most classes will behave similarly so I want to put the common code in one place
abstract class BinaryMathOperator implements IBinaryMathOperator {

	public function __construct($a, $b) { $this->a = $b; $this->b = $b; }

	public function getOperandA() { return $this->a; }
	public function getOperandB() { return $this->b; }

	// don't know about this one yet
	public abstract function operate();

}

// this class is a lot like others but does have some differences that show up in here
class AdditionMathOperator extends BinaryMathOperator {

	public function operate() { return $this->a + $this->b; }

}
IMO abstract classes that don't have any code don't make sense, so don't bother thinking about them: either do an interface or add some code in it somewhere (if sensible).
Link to comment
Share on other sites

Abstract classes are partial implementations. You use it when you want multiple implementation which share some common method definitions. This is rare and only relevant for edge cases.

 

As I already said, all classes should implement an interface, either directly or indirectly though an ancestor. You always start with an interface which defines the API. And while you write your implementations, you may in a few rare cases realize that some method definitions are always the same and should be put into an abstract parent class rather than repeated.

Link to comment
Share on other sites

You always start with an interface which defines the API. And while you write your implementations, you may in a few rare cases realize that some method definitions are always the same and should be put into an abstract parent class rather than repeated.

 

That makes way more sense then everything I have read about it in the last two days.  :thumb-up:

Edited by benanamen
Link to comment
Share on other sites

This is rare and only relevant for edge cases.

For "rare edge cases" they sure get used a lot.

 

If you find yourself almost never using abstract classes then either you've got more code duplication going on than you know about or your codebase is designed much more vertically (long inheritance hierarchies) than it is horizontally (using polymorphism).

 

As I already said, all classes should implement an interface, either directly or indirectly though an ancestor.

Classes that represent some sort of functionality, and then I'd say no more than 50% of the average codebase at an extreme. Throwing around interfaces for the sake of, what, dependency injection? is as much an anti-pattern as singletons and registries.
Link to comment
Share on other sites

Would it be correct to liken an Abstract Class and even a Interface to DB normalization?

 

Not really.  I don't think this metaphor is particularly helpful.

 

You can think of an interface as a specification, a class as a concrete blueprint and an instance as a product manufactured according to the blueprint. An abstract class would be half specification, half blueprint.

 

The diagram is actually a great demonstration why skipping the specification part and throwing abstract classes around as suggested by requinix is often a bad idea. As you can see, the Person class makes very special assumptions:

  • The first name and last name are stored in (public) attributes.
  • There's a constructor with no parameters.

Your implementation is incompatible with that? You need, for example, lazy loading? Too bad!

 

If you start with a proper specification, this doesn't happen:

<?php

interface Person
{
    public function getFirstName();

    public function getLastName();

    public function getSalary();
}

This says that a person has a first name, a last name and a salary. How the methods work is completely up to the implementor.

Edited by Jacques1
Link to comment
Share on other sites

You can think of an interface as a specification, a class as a concrete blueprint and an instance as a product manufactured according to the blueprint.

 

You make it easy for me to grasp this.

 

So would this be the same concept?

1. Client says my DB has to do A,B and C - (Specification=Interface)

2. I create a DB schema  (Concrete Blueprint = Class )

3. The DB (Product manufactured = instance according to blueprint/class)

Edited by benanamen
Link to comment
Share on other sites

But those very special assumptions are the interface. Poor class design (public properties, inflexible constructor, etc.) don't mean the pattern is useless or even bad. Sure, when you use a simple interface, the workings of the methods are up to the concrete classes, but then again they're entirely up to the concrete classes. In this instance, it's a pretty safe bet that both a contractor and an employee have a name. So in both cases, you'll be using toString() (which, in all honestly, should be getName() or something else that actually makes sense - again, it's bad design, not a bad pattern) to print that name. Why write that code in both classes? If the contractor happens to be a corporate entity, create a new CorporateContractor class and overwrite the toString() method there - you're only doing it once, and it's a specific and telling use case. Note the getSalary() method is abstract - if I'm not mistaken, that method has to be implemented in any class that extends from the Person class. So, in effect, it's very similar to your interface except that you're not writing and maintaining the same chunk of code in multiple classes.

Link to comment
Share on other sites

You've just proven my point. Everything bad about Person stems from the fact that it's an abstract class. And the one potential benefit (reusing a single line of code) is so utterly trivial that it shows how hard you're trying to come up with a legitimate example.

 

Which is exactly what I'm saying: Abstract classes are rarely useful and often abused. That does not mean abstract classes are somehow inherently bad. I'm using them myself in edge cases where there's a significant amount of common code and a trait wouldn't be appropriate. But again, this is rare.

Link to comment
Share on other sites

You've just proven my point. Everything bad about Person stems from the fact that it's an abstract class. And the one potential benefit (reusing a single line of code) is so utterly trivial that it shows how hard you're trying to come up with a legitimate example.

 

Which is exactly what I'm saying: Abstract classes are rarely useful and often abused. That does not mean abstract classes are somehow inherently bad. I'm using them myself in edge cases where there's a significant amount of common code and a trait wouldn't be appropriate. But again, this is rare.

 

Actually, I feel like you've just proven my point. It's easy to dismiss the benefits of consolidating code when taking the simple and frankly rather inane example UML diagram literally, but when you expand to a real-world scope, it makes a lot of sense in some situations. While I'm not saying that abstract classes should always be used, I am saying don't discount them out of hand. In much the same way, I think interfaces are an incredibly useful tool as well, but they don't make sense in all situations and I don't think every class should implement one unless you really, really like typing and (potentially) maintaining the same code in multiple places. Or you're using a framework that builds them for you - I remember Yii would generate skeleton controllers and pretty full models automatically. I'm not using it now, so I don't know if it still does, and I don't know if that's a thing that most frameworks do these days.

Link to comment
Share on other sites

Can you not understand, or do you not want to understand?

 

I do not “discount abstract classes”. I don't. Wherever you got this idea from, it only exist in your head. Get rid of it, so that we can have a reasonable discussion. I'm saying that abstract classes are one of the less important OOP features and shouldn't be the focus of somebody who is just beginning to learn OOP. Less important. Shouldn't be the focus. Got it?

 

We've discussed a concrete problem, and despite trying hard to justify the use of an abstract class in this scenario, you haven't convinved anybody. To the contrary. Now it's time you draw some conclusions from that.

 

As to interfaces: I understand from your topics and posts in this forum that you have a – how do I say this nicely – rather relaxed attitude towards code quality. OK. This neither surprises nor troubles me. But the topic is about learning proper OOP, and that's definitely not the right place for your hacks.

Link to comment
Share on other sites

I understand from your topics and posts in this forum that you have a – how do I say this nicely – rather relaxed attitude towards code quality. OK. This neither surprises nor troubles me.

But the topic is about learning proper OOP, and that's definitely not the right place for your hacks.

Is hardly a technical discussion.

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.