Stofa
Stofa

Reputation: 25

A lot derived classes without functonality only to "know" their type

I think there is a better solution for the following problem.

Let's say we have the following structure of classes:

class Foo
{
    public int Id { get; set; }
}

class Bar1 : Foo
{

}

class Bar2 : Foo
{

}

class Bar3 : Foo
{

}
//.. A lot more of these Foo derivations

The derived classes has no functionality. The following examples give an idea what the classes are for:

Is there a better way to identify one of these objects without derivating them?

Thanks!

Upvotes: 1

Views: 88

Answers (4)

tsachv
tsachv

Reputation: 1

You can use the visitor pattern:

    class Visitor
    {
        public void Visit(Bar1 foo)
        {
            Console.WriteLine("Bar1 ID:" + foo.Id);
        }

        public void Visit(Bar2 foo)
        {
            Console.WriteLine("Bar2 ID:" + foo.Id);
        }

        public void Visit(Bar3 foo)
        {
            Console.WriteLine("Bar3 ID:" + foo.Id);
        }
    }

I slightly modified your classes:

    abstract class Foo
    {
        public int Id { get; set; }

        public abstract void Accept(Visitor visitor);
    }

    class Bar1 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }

    class Bar2 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }

    class Bar3 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }

and now to make it all work:

        var visitor = new Visitor();
        var lst = new List<Foo> 
            { 
                new Bar1() { Id = 1 }, 
                new Bar2() { Id = 2 }, 
                new Bar3() { Id = 3 } 
            };
        foreach(var element in lst) 
        {
            element.Accept(visitor);
        }

        /* Output is:
         *
         * Bar1 ID:1
         * Bar2 ID:2
         * Bar3 ID:3
         */

The full design pattern calls for Visitor to implement an interface, which will be used in the signature of the Accept methods.

You can find more information about the Visitor design pattern here and an example of it being used in the .Net framework here.

The main drawback of using this design pattern is the coupling it creates between the visitor(s) and the concrete elements who are being visited.

For instance, when adding a new class Bar4 : Foo, it would need to override the Accept method and the Visitor would also need to updated with a new Visit method overload.

Upvotes: 0

Guido
Guido

Reputation: 308

I think the reason this feels like a problem is that there are other parts of your code that are not very object oriented.

Let me explain. Lets assume you go with the enum option. Then, whenever you want to do something with a Foo, that is different for each kind of Foo, you will need to use a switch statement, or select part of the items in the collection through some other method (like the .Where call in the enum example). As the code evolves, you will have so many of these statements that it will begin to feel wrong. Every different action over a Foo, will need to deal with all kinds of Foos. Also, Whenever you make changes to these parts of your code, you will have to make sure you separate them correctly, and that means that you will need to understand the logic behind that behaviour for all kinds of Foo at once.

If there is any chance the logic is going to get more complex, I would advise to use the interface and many classes approach over the enum approach.

Now, currently in your code, you are probably managing the difference in behaviour outside of the Foos. In order to make it more OO, you would want to let the Foos manage that difference themselves.

Upvotes: 0

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149578

If they are semantically the same and have no meaning to derivatives, you could create an Enum:

public enum SomeGreatEnum
{
   Bar1,
   Bar2,
   Bar3
}

And add a property to Foo:

class Foo
{
    public SomeGreatEnum SomeGreatEnum { get; set; }
    public int Id { get; set; }
}

Now you can:

  1. Filter:

    foos.Where(x => x.SomeGreatEnum == SomeGreatEnum.Bar1);
    
  2. Bind to GUI based on enum type.

Upvotes: 3

TIKSN
TIKSN

Reputation: 615

Better to use enumeration instead.

class Foo
{
    public int Id { get; set; }

    public FooKind Kind { get; set; }
}

Child class should enhance functionality of Parent class.

Upvotes: 2

Related Questions