Boozzz
Boozzz

Reputation: 265

OOP issue related to explicit type conversion / subclassing

This question is related to the concept of object oriented design.

In the following example code (C#), I have an abstract base class Feature, which has two subclasses: SubFeature1 and SubFeature2. In my main program, I want to instantiate each of them by giving the correspondent parameter (name of class as a string) to the unique method instantiateFeature().

When I run this code, I get an error that basically states that the type OOP_example.Feature cannot implicitely converted to OOP_example.SubFeature1 because an explicite conversion is already existing.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OOP_example
{
    class Program
    {
        static void Main(string[] args)
        {
            Organization myOrga = new Organization();

            SubFeature1 subObj1 = myOrga.instantiateFeature("SubFeature1");
            SubFeature2 subObj2 = myOrga.instantiateFeature("SubFeature2");
        }
    }

    public class Organization
    {
        Feature obj;

        public Feature instantiateFeature(string s)
        {
            if (s.Equals("SubFeature1"))
            {
                obj = new SubFeature1();
            }
            else if (s.Equals("SubFeature2"))
            {
                obj = new SubFeature2();
            }

            return obj;
        }
    }

    public abstract class Feature
    {
        public abstract void doSomething();
    }

    public class SubFeature1 : Feature
    {
        private int[] _val1;

        //constructor
        public SubFeature1()
        {
            _val1 = new int[2];
            _val1[0] = 1;
            _val1[1] = 2;            
        }

        //this is the only method that inherits from class Feature
        public override void doSomething()
        {
            //not implemented yet
        }

        //this is some other class that does not inherit from Feature
        public void doSomethingElse()
        {
            //not implemented yet
        }
    }

    public class SubFeature2 : Feature
    {
        private int[] _val1;

        //constructor
        public SubFeature2()
        {
            _val1 = new int[2];
            _val1[0] = 1;
            _val1[1] = 2;
        }

        //this is the only method that inherits from class Feature
        public override void doSomething()
        {
            //not implemented yet
        }

        //this is some other class that does not inherit from Feature
        public void doSomethingElse()
        {
            //not implemented yet
        }
    }
}

I don't want to instantiate each subclass directly, because there will be a lot of them in the future. I thought I could use the concept of Inheritance to structure my code, because some methodes (here, doSomething()) exist in all of my classes.

What is the common way to accomplish this? Can anyone show me a best practice?

Thank you!

Upvotes: 1

Views: 87

Answers (3)

aze
aze

Reputation: 850

I think the concept you are trying to use is not really inheritance but polymorphism, what you should do is create an object with the type Feature and associate with a new Feature1/2. When you use a method on one of these, it will search the "executive" type first.

Upvotes: 0

Atomosk
Atomosk

Reputation: 2017

instantiateFeature returns Feature, which can be either SubFeature1 or SubFeature2. What if you write SubFeature1 a = myOrga.instantiateFeature("SubFeature2");? Compiler can't be sure, so it shows you an error. The purpose of such abstract base class is to define some parts which is realy impotant, something enough for you to work without worring which of subclasses you are using right now. So what you do is design such Feature base class and write code, which uses only Feature variables.

EDIT, text is too large for comment

Let me show you a little example of what I'm talking about. Imagine we have subfeatures, one of them orders pizza. Now we have subclasses: OrderPizzaByPhoneFeature, OrderPizzaByEmailFeature. Both of their doSomething order pizza, but in a different way. In our application it is a user setting. Now to order pizza we call instantiateFeature and pass it "I want to order pizza" or maybe calling instantiatePizzaFeature. Inside instantiateFeature looks for settings and decides if it need to create OrderPizzaByPhoneFeature or OrderPizzaByEmailFeature. We get Feature and call it's doSomething, which does exactly what we want to do. Now if we want to add some new order type OrderPizzaByPigeonMailFeature all we need to do is to add user setting and few lines in instantiateFeature. Ordering code still works fine, it never knew about Feature subclasses. Well maybe it knew there is some ordering pizza features, but never knew how many of them exist.

Upvotes: 0

Thomas Levesque
Thomas Levesque

Reputation: 292405

The return type of your instantiateFeature method is Feature, so if you want to assign it to a SubFeature1, you need to cast:

        SubFeature1 subObj1 = (SubFeature1)myOrga.instantiateFeature("SubFeature1");
        SubFeature2 subObj2 = (SubFeature2)myOrga.instantiateFeature("SubFeature2");

But anyway, if you already know the concrete type that the method is going to return, there is no point in using a factory method; you might as well instantiate the concrete class directly. The point of a factory method is usually to abstract the calling code from the actual implementation:

        Feature subObj1 = myOrga.instantiateFeature("SubFeature1");
        Feature subObj2 = myOrga.instantiateFeature("SubFeature2");

As a side note, in your Organization class, you should declare obj as a local variable, not a field. Making it a field means that the instantiateFeature method is not thread-safe.

Upvotes: 3

Related Questions