Question

I'm fairly new to programming. At school I am currently learning to program with Java. I want to build an application where i can store my collection of books, records, boardgames and such. Started making an class diagram to get me started and when that was finished started programming. I have an Artikel class which is abstract. Then I have for examaple my book class which extends from Artikel.

Example of class diagram

Now when i started programming I noticed that in all subclasses i basically needed to do the exact same thing, with a few atributes changes. I thought of making Artikel not abstract and put an interface between Artikel and the other classes, but then i would still be copying a lot of work.

It's also possible to make an seperate class which inherits from Artikel where I can put all the methods, but then there the methods would still be needed to made three times, one for each subclass right?

How would you guys design something like this? Is it a bad design choice if I keep Artikel as abstract?

Was it helpful?

Solution

Note: please forgive the C# syntax, but the principle of the answer is the same for Java and C#.

Now when i started programming I noticed that in all subclasses i basically needed to do the exact same thing

Based on this, it seems like you think abstract classes are only allowed to declare abstract methods. This is not the case.

An abstract class is a class that cannot be instantiated directly (only its derivations can be instantiated). An abstract method is a method in an abstract class which must be implemented in the derived class.

But an abstract class can have non-abstract methods:

public abstract class Artikel
{
    public int ArtikelId { get; set; }

    public string SayHello()
    {
        return "Hi, I'm artikel " + ArtikelId;
    }
}

When you derive Artikel into subclasses, you do not need to repeat the method body of the SayHello method. Its body has been declared in the base class and can be used by all of the derived classes.

I thought of making Artikel not abstract and put an interface between Artikel and the other classes

Interfaces prevent the ability to create a common method body. If you were to use an interface:

public interface IArtikel
{
    string SayHello();
}

Then you will be required to implement this method separately in every class:

public class Book : IArtikel
{
    public string SayHello()
    {
        // custom book logic
    }
}

// And the same for all other derived classes.

It's also possible to make an seperate class which inherits from Artikel where I can put all the methods, but then there the methods would still be needed to made three times, one for each subclass right?

Don't take this the wrong way, but your attempts at solving this suggest you don't really master OOP. If this SeparateClass was created as another (4th) subclass from Artikel, how would you expect e.g. the Book class to rely on the methods found in SeparateClass?

Is it a bad design choice if I keep Artikel as abstract?

Keep Artikel abstract, but give it non-abstract methods (i.e. with method bodies) for each method that you are now copy/pasting between all of its subclasses.

OTHER TIPS

You can have a base class as an abstract class which implements the Artikel interface. In the abstract class you can define the common implementation. Then you can derive LP, Book and Boardgame from that super class. In my opinion it is better to have a abstract class rather than copying the same code in all 3 sub classes.

I think your problem has nothing to do with abstract classes or interfaces. Your use of an abstract base class in this case is perfectly correct.

It's not completely clear what you mean with this:

I noticed that in all subclasses i basically needed to do the exact same thing, with a few atributes changes.

I'm guessing that you're talking about the addArtikel() and removeArtikel(), and it's not clear what exactly those are doing, but I'm guessing it has something to do with a database or, for a learning project, just a list or hash table in memory. And the implementation probably have a lot of duplicated code for the common properties like name and publisher.

How best to avoid the code duplication is hard to say without seeing that code, but part of it could be to make addArtikel() and removeArtikel() in the superclass not abstract, but have them deal with the common properties, so that the overriding implementations in the subclasses can reuse this logic by calling super.addArtikel() and removeArtikel().

However, the real design problem here is that addArtikel() and removeArtikel() should not be in the Artikel class at all because they have nothing to do with the data model itself. They should be part of a class that models what the items are added to or removed from. Typical design patterns for this have classes called DAO (Data Access Object) or Repository.

First, for your problem statement, you should have the parent Artikel , an abstract class, implement the common methods in it which have the same functionality, so you don't have to repeat yourself in every child class. Methods that needs to be implemented in a specific way in child classes, set as abstract.

Why you are making a class Abstract? Because it shouldn't be instantiated, and only children could be. Also if you need to leave method implementation to child class, it should be abstract which is only possible in abstract class.

Now, Interface vs Abstract. In theory, read this https://beginnersbook.com/2013/05/abstract-class-vs-interface-in-java/

In practice, Interface is kind of a specification. Means, there is no logic in it. All methods should be implemented by class implementing it (Prior to Java 10). Abstract class can have specs and implementation too.

In general, for model/entity classes, the parent is abstract class.

When I'm asked in job interview what's an abstract class and how it differs from regular class I reply: You can't create an object from an abstract class. First you need to extend it and it's a job of a regular class. They nod their head and go to next question.

That's a constraint and constraints help programmers think by narrowing down the choices they can make. The job of an abstract class is to always point "North". By "North" I mean responding to property/method calls from classes who (in your case) did not define method addArtikel.

Here is an example from PayPal repository where a class extends an abstract class:

class PayPalLogger extends AbstractLogger

It so happens that this abstract class also implements a well known PSR-3 interface.

Here is another example from PayPal where class both extends and implements:

class PayPalResourceModel extends PayPalModel implements IResource

Digging deeper you find this:

<?php
namespace PayPal\Rest;
/**
 * Interface IResource
 *
 * @package PayPal\Rest
 */
interface IResource
{
}

This example is interesting, because nothing is actually asked of programmer who is going to implement this interface. Maximum freedom.

Now, the interface is like a map of a territory, or a todo list for a programmer. It reminds what requirements are. When implementing an interface programmer MUST define all methods listed inside interface file. It throws an error if you skip one. While it's not a case with abstract classes you see.

Going back to your "problem":

  1. AbstractArtikel should implement an interface IArtikel and define fallback functionality.
  2. ArtikelLP, ArtikelBook and ArtikelBoardgame should extend AbstractArtikel and redefine methods where appropriate. Here not only similarities, but also differences start to be important.
  3. Create ArtikelLP, ArtikelBook and ArtikelBoardgame objects.

Can an interface extend an interface? This I don't know.

Licensed under: CC-BY-SA with attribution
scroll top