Solved

C# inheritance design: virtual or abstract

Posted on 2015-02-06
4
112 Views
Last Modified: 2015-02-09
I have the below abstract class:
public abstract class ProcessorGateway
    {
        public abstract void AuthorizeTransaction(ProcessorGatewayContext context);

        public abstract string GetTransactionDetailsResponseReason(ProcessorGatewayContext context, string _transID);

        public abstract ProcessorGatewayContext NewContext();

        private bool _isLive;

        public bool IsLive
        {
            get { return _isLive; }
            set { _isLive = value; }
        }
    }

Open in new window

Until now, there was only one child class called AuthorizeNetGateway which was extending the above mentioned abstract class and overriding all of its methods.

Now, we have a need for another child class, but this new child class does not have all the functionality yet like the AuthorizeNetGateway child class. For example, it does not yet require GetTransactionDetailsResponseReason functionality.

Having said that, since GetTransactionDetailsResponseReason is an abstract method, it requires that all child classes override it.

What would be the best design option at the moment?
Option 1:
Override GetTransactionDetailsResponseReason in the new child class with an empty implementation.

Option 2:
Change GetTransactionDetailsResponseReason method into a Virtual method (although I don't know what the side effects of this would be for the existing AuthorizeNetGateway child class)
0
Comment
Question by:pzozulka
  • 2
4 Comments
 
LVL 40

Accepted Solution

by:
Jacques Bourgeois (James Burger) earned 500 total points
Comment Utility
First of all, because your base class does not provide any implementation, you would have been better to define an Interface.

You use an abstract class when the base class implements (does) a few things, but cannot do everything.

For instance, a Music document and a Video document have a lot in common. They have a Title, they have a Producer, they have a RecordedDate and so on. The code for these properties is the same no matter if it is Music or Video. So the best way to deal with that would be to create a Document class that has all the code to handle these properties, and inherit from Document to create Music and Video.

But Music and Video also have a duration component, that should be taken from the actual file. And the code to retrieve the duration from a .wav file and from a .wmv file is not the same. This is where the abstract methods come into play. The Document class cannot provide the code for the Duration property, because it is different for all the derived classes. So you declare it abstract to force the derived classes into providing it.

When all the code needs to be defined in the derived classes and none can be defined in the base class, then you are in a situation were an interface. You implement the interface in the derived classes instead of inheriting. At first, the differences between a completely abstract class and interface is not


Now for your question. Basically, Option 1, Option 2 or an Interface do not have that great an impact in the derived classes, because you do nothing in your class but force an override, and you do nothing in an interface but force the implementation. I have never made the kind of switch you suggest in Option 2, because I would have used an Interface, but at first sight, because Option 1 forces you to override and Option 2 enables you to override, the logic would be that it would have no impact, since everything is already overridden. So I do not see (in my mind) any problem with your already existing derived class, but Option 1 is better, because Option 2 would force you to create real methods (only { }, but that makes a difference for the compiler), work that brings no change. You like to work for nothing?

As for your new class, if you use Option 1 the methods that do nothing will be in the derived class, while with Option 2 they will be in the base class. Does it really matter to know where a method that does nothing is defined?

You will need empty methods no matter what.

Usually, empty methods are not a good thing.

How will you tell the users of you new class "Hey, I have this method, but do not call it, it does nothing." I see them coming at you with their long teeths, to eat you, because they lost 2 days trying to find a bug, while it was simply that your method that did not return any value.

If you inherit from a base class that does nothing, or implement an interface, that means that you want to use polymorphism, that is that you want in some circumstances to be able to use both classes in the same place by defining variables or parameters of the base type. If not, then inheriting serves nothing.

You thus have to make sure that the empty methods won't break the application if they are called through the base class. If I go back to my example, let's say that you think that not implementing the Duration property on the Music class is you might have a method that receives a Document as a parameter. That means that it can receive either a Music object or a Video object. If you call the Duration property on a Document, and it is Music, but that the Duration property does nothing, it will return zero. What will happen in the method that uses the document if, for some reason, it divides a value by the Duration. A division by zero is not acceptable in most conditions. Boom, your empty property just broke an application.

The main thing is: how long with your "not yet require" last? If it is temporary, while you are still in development, no problem if the situation is well known by everybody. But I would never leave such temporary stuff out into production, the dangers of a disaster are too big.
0
 
LVL 8

Author Comment

by:pzozulka
Comment Utility
Thank you, this information is invaluable.

I think "not yet required" might last up to a year or more. When I implemented the base class, I thought all children of it will have the ability to use the GetTransactionDetailsResponseReason method, but apparently, when the new child class came along, I realized it does not support this functionality (at least for now).

The reason I implemented this method as an abstract class is because the existing AuthorizeNet child class needs to use the IsLive property of the base class. It checks for this property inside the override GetTransactionDetailsResponseReason method using base.IsLive.

Here's how IsLive is assigned, and how the GetTransactionDetailsResponseReason is called.

ProcessorGateway Gateway = GatewayConstants.GetGateway("Authorize.Net"); 
// Here Gateway will reference the AuthorizeNet child class.
if(System.Configuration.ConfigurationManager.AppSettings["CreditCardLiveMode"] .ToString() == "true")
{
   Gateway.IsLive = true;
}
string reason = Gateway.GetTransactionDetailsResponseReason(context, _transId);

Open in new window


From your excellent explanation, my conclusion was that the best way was to not make the GetTransactionDetailsResponseReason method an abstract method at all since not all children have this functionality. This would definitely solve my problem for my original question in this post, but then would create a new problem, for the existing AuthorizeNet child class.

Perhaps I should modify the above code to not use Polymorphism since it is hard-coded to only use "Authorize.Net" anyway in the calling method. And instead of using Gateway.IsLive, I can just modify the GetTransactionDetailsResponseReason  method to accept another boolean parameter, and instead of inside that method checking if base.IsLive is true, I should simply check if the passed boolean parameter is true.
0
 
LVL 40

Expert Comment

by:Jacques Bourgeois (James Burger)
Comment Utility
If for the moment you need GetTransactionDetailsResponseReason only in one class, it does not belong to the base class. Move it in the class where you use it. That way it won't appear as a phantom in the other derived classes and possibly cause problems if you use one of these through a base class variable or parameter.

If later you find that you need it in all the other classes, then bring it back as an abstract in the base class.

If you find otherwise that you need it in only some of the classes, first see if it would be used through polymorphism. If not, then simply add the method in the classes that need it, without any obligation from higher up. If however you see situations that would require many of these classes to be used interchangeably at the same place, then create an interface and have all the classes that use it implement that interface.

You can inherit from only one class, but then implement many interfaces if you have special needs for only some of the classes underneath the base class.
0
 
LVL 7

Expert Comment

by:Camillia
Comment Utility
Thanks, Jacques. One of the best explanations for abstract and interface usage. It helped me a lot as well.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now