Link to home
Start Free TrialLog in
Avatar of pzozulka
pzozulka

asked on

C# inheritance design: virtual or abstract

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)
ASKER CERTIFIED SOLUTION
Avatar of Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger)
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of pzozulka
pzozulka

ASKER

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.
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.
Avatar of Camillia
Thanks, Jacques. One of the best explanations for abstract and interface usage. It helped me a lot as well.