简体   繁体   中英

OOP Design: Concrete Class having different Operations with Same Base Class

I am wondering if the following code can be written in C#:

AbstractClass a = new ConcreteClass1();
a.Operations.Method1();

AbstractClass b = new ConcreteClass2();
b.Operations.Method2();

where Method1() is exclusive to the ConcreteClass1 instance and Method2() is exclusive to the ConcreteClass2() instance. As a result, a.Operations.Method2() and b.Operations.Method1() would be invalid.

This is not possible by design - a and b have the same type, and the compiler will treat them as such. The only way to make it work is by using runtime exceptions.

The concept behind using abstract classes or interfaces conflicts with what you are attempting to do; it sounds like ConcreteClass1 and ConcreteClass2 do not server the same purpose, should they still use the same abstract base class?

I don't know what exactly you are trying to do - so I'll provide a few options:

Use interfaces to show that specific classes implement specific operations:

interface IOperation1
{
    void Operation1();
}

interface IOperation2
{
    void Operation2();
}

Then reference the interfaces based on what you are trying to achieve.

If Method1 and Method2 are supposed to be invoked at the same time, consider a design where AbstractClass declares the method to be invoked, and the concrete classes do different operations based on that:

abstract class AbstractClass
{
   ...
   abstract void DoSomeOperation();
}

class ConcreteClass1 
{
   override void DoSomeOperation() 
   {
      this.Operations.Method1();
   }
}

class ConcreteClass2 
{
   override void DoSomeOperation() 
   {
      this.Operations.Method2();
   }
}

It's okay for ConcreteClass1 and ConcreteClass2 to have some different methods, but share some functionality that they both inherit from AbstractClass . (If you cast them as their base type then you can only call common methods that they inherit from the base type.)

It sounds like the difference between whether a concrete class uses Method1 or Method2 is an internal detail that should be handled inside the class. The class should know what method it needs to call. In fact, does a consumer of that class even need to know that it depends on Operations ? Probably not. Consumers should just call a method on the class, and then whether that class uses Operations.Method1 , Operations.Method2 , or even depends on Operations at all is an internal implementation detail.

Maybe what you want is something like this:

public abstract class AbstractClass
{
    public abstract void DoSomething();
}

public class Operations
{
    public void Method1()
    {
        //Does something
    }

    public void Method2()
    {
        //Apparently does something comopletely different
    }
}

public class ConcreteClass1 : AbstractClass
{
    private Operations _operations;

    public override void DoSomething()
    {
        _operations.Method1();
    }
}

public class ConcreteClass2 : AbstractClass
{
    private Operations _operations;

    public override void DoSomething()
    {
        _operations.Method2();
    }
}

Operations should only be in the base class if it's required that every derived class will use it. (That doesn't happen too much. If all of the derived classes have the same behavior, why isn't it in the base class?) If that's the case then you can hide it in the base class, like this:

public abstract class AbstractClass
{
    private Operations _operations;

    protected Operations Operations { get { return _operations; } }
    public abstract void DoSomething();
}

That way it's exposed to the derived classes but hidden from everything else.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM