1

Right now, I am learning OOP, mainly in c#. I am interested in what are the main reasons to make a class that can't be instantiated. What would be the correct example of when to make an abstract class? I found myself using the abstract class in inheritance way too enthusiastically. Are there some rules when class is abstract in system and when class should not be abstract? For instance, I made doctor and patient classes which are similar in some way so I derived them both from abstract class Person (since both have name and surname). Was that wrong? Sorry if the question is stupid, I am very new at this.

Martlark
  • 14,208
  • 13
  • 83
  • 99
Biljana M.
  • 359
  • 1
  • 4
  • 22
  • possible duplicate of [When to use abstract classes?](http://stackoverflow.com/questions/2570814/when-to-use-abstract-classes) – pNre Sep 24 '13 at 09:50
  • there is no rules on when to make abstract, it is only the need that drive such things. when I said rules means if you make or don't make abstract class your software will still work :). But you are right if you make "person" as abstract class as Person has nothing to do at all in your apps, but still define a Person type object in application. – Sumit Gupta Sep 24 '13 at 09:54

8 Answers8

2

There are a couple of things no one has pointed out so far, so I would just like to point them out.

You can only inherit from one base class (which could be abstract) but you can implement many interfaces. So in this sense inheriting an abstract class is a closer relationship than implementing an interface.

So if you later on realize that you have a need for a class which implements two different abstract classes you are in deep shit :)

To answer your question "when to make an abstract class" I'd say never, avoid it if possible, it will never pay off in the long run, if the main class is not suitable as a ordinary class, it probably isn't really needed as abstract either, use an interface. If you ever get in the situation where you are duplicating code it might be suitable with an abstract class, but always have a look at interfaces and behavioral patterns first (ex the strategy pattern solves a lot of issues people wrongly use inheritance to solve, always prefer composition over inheritance). Use abstract classes as a last hand solution, not as a design.

To get a better understanding of OOP in general, I'd recommend you to have a look at Design Patterns: Elements of Reusable Object-Oriented Software (a book) which gives a good overview of OO-design and reusability of OO-components. OO-design is about so much more than inheritance :)

flindeberg
  • 4,887
  • 1
  • 24
  • 37
  • One feature which sets abstract classes apart from interfaces is that an assembly can define a public abstract class but not allow any other assembly to define classes deriving from it. If an assembly that defines such a class defines e.g. four classes that derive from it, code receiving a non-null reference of the abstract type can be assured that it will refer to an instance of one of those four types. – supercat Sep 26 '13 at 18:41
  • @supercat I did not know that. But in what sense is that useful from a design perspective? – flindeberg Oct 11 '13 at 11:31
  • Polymorphism through virtual method calls is great, but has some limitations. It does not work well for double-dispatch scenarios, where different code is required for different combinations of operands. As a simple example, consider a `BigInteger` class with subclasses `SimpleBigInteger` which has a field of type `long`, and `ReallyBigInteger` which has a field of type `uint32[]`. Since a lot of values will in fact be small enough to fit in a `long`, having a separate class to handle that case may be useful even though it will mean... – supercat Oct 11 '13 at 15:50
  • ...that a method like `Divide` will need to be coded separately for every combination of operand types. One could easily design `BigInteger` so that for every pair of types, only one would have to know about the other; one could then create a new type that would interact with all the existing ones without having to change any of the code for those existing types. Unfortunately, if `BigNumber` is open to outside inheritance, there would be no way to prevent outside code from deriving two new types, neither of which knows about the other, and then trying to perform math on them together. – supercat Oct 11 '13 at 15:57
  • There are some ways one could design an `IBigNumber` interface that would allow arbitrary implementations to interact (e.g. if it had a `NumberOfWords` property and `GetWord(int)` method, a `SimpleBigInteger` could return either one or two for `NumberOfWords` (depending upon its magnitude) and have `GetWord` return either the upper or lower 32 bits of its magnitude, but classes that knew about each other could be more efficient. – supercat Oct 11 '13 at 16:04
1

For Example: you have a scenario where you need to pull data from different sources, like "Excel File,XML,any Database etc" and save in one common destination. It may be any database. So in this situation you can use abstract classes like this.

abstract class AbstractImporter 
{
    public abstract List<SoldProduct> FetchData();
    public bool UploadData(List<SoldProduct> productsSold)
    {
        // here you can do code to save data in common destination 
    }
}

public class ExcelImporter : AbstractImporter 
{
  public override List<SoldProduct> FetchData()
  {
  // here do code to get data from excel

  }
}

public class XMLImporter : AbstractImporter 
{
  public override List<SoldProduct> FetchData()
  {
  // here do code to get data from XML

  }
}

public class AccessDataImporter : AbstractImporter 
{
  public override List<SoldProduct> FetchData()
  {
  // here do code to get data from Access database

  }
}

and calling can be like this

    static class Program
    {

          static void Main()
          {
             List<SoldProduct> lstProducts;
             ExcelImporter excelImp = new ExcelImporter();
             lstProducts = excelImp.FetchData();
             excelImp.UploadData(lstProducts);


             XMLImporter xmlImp = new XMLImporter ();
             lstProducts = xmlImp.FetchData();
             xmlImp.UploadData(lstProducts);


             AccessDataImporterxmlImp accImp = new AccessDataImporter();
             lstProducts = accImp .FetchData();
             accImp.UploadData(lstProducts);


          }
    }

So, in Above example, implementation of data import functionality is separated in extended (derived) class but data upload functionality is common for all.

Martlark
  • 14,208
  • 13
  • 83
  • 99
Neeraj Kumar Gupta
  • 2,157
  • 7
  • 30
  • 58
  • This is a great example, but I was wondering, wouldn't it be as good to implement UploadData functionality through interface instead of abstract class? – Biljana M. Sep 24 '13 at 11:13
  • So then you have to do UploadData functionality in each class where you implement interface, when upload data functionality is same for all, so why we repeat code in each implementation. that is a significance of abstract class. – Neeraj Kumar Gupta Sep 24 '13 at 11:18
  • A word of warning here, what happens if you have to upload to multiple sources? This is not a good design, only use inheritance in this manner when you are 147.3% sure the requirements will never change. The upload is this sense is not even connected to the fetching... it should not be in the same class! – flindeberg Sep 24 '13 at 12:56
  • This was just an example not the real implementation @flindeberg on production – Neeraj Kumar Gupta Sep 24 '13 at 13:30
  • @NeerajKumarGupta Of course, and that was the reason for my comment, abstract classes are often only useful in teaching scenarious, not in real life :) – flindeberg Sep 24 '13 at 13:53
0

In essence what you have done is fine if you never want to instantiate a Person class, however as I'm guessing you may want to instantiate a Person class at some point in the future then it should not be abstract.

Although there is an argument that you code to fix current issues, not to cater for issues which may never arise, so if you need to instantiate Person class do not mark it as abstract.

Abstract classes are incomplete and must be implemented in a derived class... Generally speaking I tend to prefer abstract base classes over interfaces.

Look into the difference between abstract classes and interfaces...

"The difference between an abstract class and an interface is that an abstract class can have a default implementation of methods, so if you don't override them in a derived class, the abstract base class implementation is used. Interfaces cannot have any implementation." Taken from this SO post

Community
  • 1
  • 1
Paul Zahra
  • 9,522
  • 8
  • 54
  • 76
  • I didn't find interface useful here because patient and doctor in that system would not share any methods. However, if they did, then interface would be useful. But I find abstract class restricting and that was why I wondered. I am totally confused. Started as procedural programmer now this seems VERY different. – Biljana M. Sep 24 '13 at 10:19
  • Indeed, where base methods will not vary among derived classes abstract is good, but if they were to vary then interface would provide a template, and the derived classes would provide the implementation. Or of course you could allways override the abstract class' methods and provide different method implementations in derived classes... i pointed you at the differences between interfaces and abstract classes as it's a good way to learn about both. – Paul Zahra Sep 24 '13 at 11:19
0

As already stated, noone will force you to use abstract classes, it is just a methodology to abstract certain functionality which is common among a number of classes.

Your case is a good example where to use abstract classes, because you have common properties among two different types. But of cause it restricts you to use Person as a type by itself. If you want to have this restriction is basically up to you.

In general, I would not use abstract classes for Model like classes as you have unless you want to prevent Person from being instantiated.

Usually I use abstract classes if I also have defined an interface and I need to code different implementations for this interface but also want to have a BaseClass which already covers some common functionality for all implementations.

MichaC
  • 13,104
  • 2
  • 44
  • 56
  • Thanks for the answer. The reason I did person as an abstract is because it was supposed to be medical institution application. Therefor, only Patient or Doctor should have instances in that system (or maybe Visitor). Person in such system would have no meaning (maybe?). – Biljana M. Sep 24 '13 at 10:14
0

Deriving both 'Doctor' and 'Patient' from an abstract class 'Person' is fine, but you should probably make Person just a regular class. It depends on the context in which 'Person' is being used, though.

For example, you might have an abstract class named 'GameObject'. Every object in the game (e.g. Pistol, OneUp) extends 'GameObject'. But you can't have a 'GameObject' by itself, as 'GameObject' describes what a class should have, but doesn't go into detail as to what they are.

For example, GameObject might say something like: "All GameObjects must look like something'. A Pistol might extend on what GameObject said, and it says "All Pistols must look like a long barrel with a grip on one end and a trigger."

DeadlyFugu
  • 152
  • 5
  • Yes, that sounds right. However, my logic was like: person is too vague in system where only doctor or patient matter. If we instantiate person we must know immediately if it's doctor or patient. But if they had some methods in common, then would there be good option to instantiate person? – Biljana M. Sep 24 '13 at 10:17
  • Ah, like I said, it depends on the context in which 'Person' is being used. If only 'Doctor' and 'Patient' matter, then 'Person' should be abstract. – DeadlyFugu Sep 24 '13 at 10:56
0

This is probably a non-academic definition, but an abstract class should represent an entity that is so "abstract" that make no sense to instantiate it.

It is often used to create "templates" that must be extended by concrete classes. So an abstract class can implement common features, for example implementing some methods of an interface, an delegate to concrete classes implementation of specific behaviors.

davioooh
  • 23,742
  • 39
  • 159
  • 250
0

The key is whether instantiation of that class ever makes sense. If it will never be appropriate to instantiate that class, then it should be abstract.

A classic example is a Shape base class, with Square, Circle and Triangle child classes. A Shape should never be instantiated because by definition, you don't know what shape you want it to be. Therefore, it makes sense to make Shape an abstract class.

Simon Trewhella
  • 2,124
  • 3
  • 23
  • 23
  • I get it! Or like Animal. You can never instantiate an animal if you don't know which one. – Biljana M. Sep 24 '13 at 11:17
  • As long as you don't want to have a generic type of type Shape :D – Paul Zahra Sep 24 '13 at 11:23
  • And as long as the shapes share some kind of internal behavior. Do they really do this? Or could they be composed differently? It is a good schoolbook example, but doesn't really fit in general purpose programming. Also, why shouldn't it be an interface based on your description? – flindeberg Sep 24 '13 at 13:00
  • I'm presuming of course that the utilization of inheritance was appropriate, since the question didn't pertain to that. It is entirely plausible that Shapes would share behaviour and data, such as things to do with drawing. – Simon Trewhella Sep 26 '13 at 01:41
  • @flindeberg: I would expect that in something like a 2d drawing package, every shape would have methods to get a bounding box, move the origin, render it to a graphics context, and convert between persistent and editable forms. My inclination would be to use references of interface type IShape, but also define an abstract Shape class which included a lot of the common code. – supercat Sep 26 '13 at 18:46
  • @supercat I agree with you, I just wanted to point out that an interface describing the shared functionality would be a better idea. I realize now that the comment might seem a bit harsh. I apologize for that. – flindeberg Oct 11 '13 at 11:29
0

Incidentally, another issue which hasn't yet been mentioned is that it is possible to add members to an abstract class, have existing implementations automatically support them, and allow consumers to use implementations which know about the new members and implementations which don't, interchangeably. While there are some plausible mechanisms by which a future .NET runtime could allow interfaces to work that way as well, at present they do not.

For example, if IEnumerable had been an abstract class (there are of course good many reasons why it isn't), something like a Count method could have been added when its usefulness became apparent; its default implementation of Count could behave much like the IEnumerable<T>.Count extension method, but implementations which knew about the new method could implement it more efficiently (although IEnumerable<T>.Count will try to take advantage of implementations of ICollection<T>.Count or ICollection.Count, it first has to determine whether they exist; by contrast, any override would know that it has code to handle Count directly).

It would have been possible to add an ICountableEnumerable<T> interface which inherited from IEnumerable<T> but included Count, and existing code would continue to work just fine with IEnumerable<T> as it always had, but any time an ICountableEnumerable<T> was passed through existing code, the recipient would have to recast it to ICountableEnumerable<T> to use the Count method. Far less convenient than having a directly-dispatched Count method which could simply act directly on IEnumerable<T> [the Count extension method isn't horrible, but it's far less efficient than would be a directly-dispatched virtual method].

If there were a means by which an interface could include static methods, and if the class loader, upon finding that a class Boz which claimed to implement IFoo, was missing method string IFoo.Bar(int), would automatically add to that class:

stringIFoo.Bar(int p1) { return IFoo.classHelper_Bar(Boz this, int p1); }

[assuming the interface contains that static method], then it would be possible to have interfaces add members without breaking existing implementations, provided that they also included static methods that could be called by default implementations. Unfortunately, I know of no plans to add any such functionality.

supercat
  • 77,689
  • 9
  • 166
  • 211