-4

I have a class A and class B, both derive from the same parent class. Each object has a state machine inside it that defines it's behaviour. The behaviour is different though depending on if the object is of a class A or B. My approach to this is to differentiate what class an object is in the state machine and behave accordingly. Is there a better way to do this?

  • virtual methods is the usual way to have derived class have behavior differ from the parent and each other. Is your state machine an object you inject? Is there some other complication why virtual methods are not enough, or otherwise avoided? – Theraot Nov 16 '20 at 11:53
  • 1
    Not the downvoter, but trying to help explain a likely cause for the downvote since you're new here: while the core question itself is valid and on-topic, the quality of the question leaves a lot to be desired. A basic code example would've helped understand your exact situation and intentions. The vaguer your question is, the more possible scenarios answerers have to all account for, and the higher the chance that you get a generic but widely applicable answer instead of an answer that's tailored to your specific situation. – Flater Nov 16 '20 at 12:22
  • This question is all solution and no requirements. We can always suggest a different way. How are we supposed to know what would be better without knowing what problem were solving? – candied_orange Nov 16 '20 at 15:24
  • Could you elaborate a bit more? E.g., you say "Each object has a state machine inside it", but then you also say "My approach to this is to differentiate what class an object is". Here's what's unclear - if each object has a state machine inside (which I interpreted to mean it implements its own state machine internally), then why do you have to check the objects class (from the outside)? Or is it that when you say "has a state machine" you just mean that it has some data in it that describes state, and the state machine (behavior) is actually implemented outside of it? – Filip Milovanović Nov 16 '20 at 16:15
1

Your question is a bit light on specific context. One particular distinction here is if your A-state machine and B-state machine can be abstracted into a common ancestor, the base-state machine.

Specifically, are you able to abstract all of the state machine features that A and B use, so that the logic for A using its AStateMachine is exactly the same as B using its BStateMachine?


If yes, then simply use this base-state machine as the type. This is the best in terms of reusability. When this is possible, this is the best approach to take.

public class BaseStateMachine {}
public class AStateMachine : BaseStateMachine {}
public class BStateMachine : BaseStateMachine {}

public class Base
{
    private readonly BaseStateMachine _state;

    public Base(BaseStateMachine state)
    {
        _state = state;
    }

    public void DoJob()
    {
        Console.WriteLine(_state.MyValue);
    }
}

public class A : Base
{
    public A(AStateMachine state) : base(state)
    {

    }
}

public class B : Base
{
    public B(BStateMachine state) : base(state)
    {

    }
}

This is by far the easier approach, since the logic for both A and B only has to be written once (in Base). However, this relies on the idea that the handling between them is similar enough that the state machines have the same reusable interface.

If this is possible, this is usually the best approach to take. But that's an if...

Note: I'm ignoring the distinction between interfaces and base classes here, as they are equivalent for the current discussion. Whether you use the BaseStateMachine class or IStateMachine interface, the same principle applies.


If no, this is not possible, and the logic for A using its AStateMachine is fundamentally different from B using its BStateMachine, then your Base should define abstract/virtual methods where A and B can override it with their own implementation. Since the assumption here is that there is no default implementation before it gets overridden, abstract is the way to go.

public class AStateMachine
{
    public string GetFoo() => "State from A";
}

public class BStateMachine
{
    public int GetBar() => 123;
}

public abstract class Base
{
    protected abstract string GetStateValue();

    public void DoJob()
    {
        string result = GetStateValue();

        Console.WriteLine(result);
    }
}

public class A : Base
{
    private readonly AStateMachine _state;

    public A(AStateMachine state)
    {
        _state = state;
    }

    protected override string GetStateValue()
    {
        return _state.GetFoo();
    }
}

public class B : Base
{
    private readonly BStateMachine _state;

    public B(BStateMachine state)
    {
        _state = state;
    }

    protected override string GetStateValue()
    {
        int stateValue = _state.GetBar();

        return stateValue.ToString();
    }
}

Notice how Base itself doesn't have or use a state machine. Since the two state machines are inherently different, they shouldn't be stored in Base, but rather in A and B themselves. Base can access its virtual methods to gain access to the content of the state machine. Base cannot access the state machine directly, since Base cannot account for every different way of handling every different state machine (doing so would constitute an OCP violation).

This is more cumbersome to write because you need to individually implement the state machine handling logic for both A and B, but it gives you a great degree of freedom on how these machines can be handled in wildly different ways while still ensuring that your Base has a reusable way of accessing these wildly different state machines.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.