Skip to main content
Post Undeleted by ChrisF
Post Deleted by ChrisF
Rollback to Revision 3
Source Link
ChrisF
  • 38.9k
  • 11
  • 127
  • 168

WorkingThe interface segregation principle is focused more on deleting my postscompletely irrelevant functionality. Here it's not so clear cut.

A blatant example of a violation of ISP is a Scrollbar interface with positive answersa setText function inherited from Widget, when a scrollbar won't even show any text. GoingIn such a case, the function may even be documented as irrelevant to callers, and to attempt to call such a function on a scrollbar may indicate a logical error.

Such blatant violations of ISP tend to be most foul, with monolithic interfaces that might have 200 functions with only 20 of them being relevant for the actual object in question. I see it often in GUI designs which are based around massive inheritance hierarchies, and often with documentation mechanisms trying to filter out the enormous amount of irrelevant derived functionality.

In your case, I think it's a bit different since given a function like this:

virtual bool handleInput(KeyEvent aKeyEvent, ...) = 0;

... it's still relevant to clients whether or not a view handles keyboard input. The fact that it doesn't is still relevant information, and worth calling the function to find out. So I don't see this as a clear violation of ISP.

You could try to split up the interface into multiple interfaces like IKeyboardHandler, but it's likely to make things harder rather than easier. It's worth noting the scope here in terms of dependencies.

A game will typically only have a handful of such views. You might have a main menu screen of sorts, splash screen, HUD, game view, maybe an in-game pie menu or something. It's a handful of views. The clients will also tend to be few in number, maybe just one broad client which is the one handling events from the operating system and calling the relevant view functions. So it's very limited in scope/scale when it comes to the number of dependencies, and that's a sign that you don't need to try too hard to come up with a great engineering solution, and that doing so may very well contradict your goals for maximum negative votes!ease of maintenance (ease of change).

Avoiding the Dynamic Cast

That said, just for completeness, I'll show you a simple way to avoid the cast in these kinds of scenarios. You can do this:

class IView{
public:
    ...

    // Returns null if keyboard handling is unsupported.
    virtual IKeyboardHandler* keyboard() = 0;

    // Returns null if mouse handling is unsupported.
    virtual IMouseHandler* mouse() = 0;
};

... view types that don't need inherit from (implement) IKeyboardHandler can simply return null, e.g. Ones that do can simply return this;. This way you can find out if a view supports keyboard handling with an interface query which doesn't involve casting, and if so, handle keyboard input for that view.

Taking this technique further to a greater degree of flexibility will often have you approaching COM-style designs (which does involve casting but hides it from the client), and even further, entity-component systems (which can be very useful to know about as a game developer, but probably outside of this view context). Yet I think this is absolute overkill for your case even with the basic form, and likely to just add more burdens upfront without alleviating any later.

Yet this basic version shown above can be a useful design technique if you had, say, functions in your system which can work strictly with IKeyboardHandler, and you potentially have things other than views which might implement this keyboard handling interface.

Working on deleting my posts with positive answers. Going to try for maximum negative votes!

The interface segregation principle is focused more on completely irrelevant functionality. Here it's not so clear cut.

A blatant example of a violation of ISP is a Scrollbar interface with a setText function inherited from Widget, when a scrollbar won't even show any text. In such a case, the function may even be documented as irrelevant to callers, and to attempt to call such a function on a scrollbar may indicate a logical error.

Such blatant violations of ISP tend to be most foul, with monolithic interfaces that might have 200 functions with only 20 of them being relevant for the actual object in question. I see it often in GUI designs which are based around massive inheritance hierarchies, and often with documentation mechanisms trying to filter out the enormous amount of irrelevant derived functionality.

In your case, I think it's a bit different since given a function like this:

virtual bool handleInput(KeyEvent aKeyEvent, ...) = 0;

... it's still relevant to clients whether or not a view handles keyboard input. The fact that it doesn't is still relevant information, and worth calling the function to find out. So I don't see this as a clear violation of ISP.

You could try to split up the interface into multiple interfaces like IKeyboardHandler, but it's likely to make things harder rather than easier. It's worth noting the scope here in terms of dependencies.

A game will typically only have a handful of such views. You might have a main menu screen of sorts, splash screen, HUD, game view, maybe an in-game pie menu or something. It's a handful of views. The clients will also tend to be few in number, maybe just one broad client which is the one handling events from the operating system and calling the relevant view functions. So it's very limited in scope/scale when it comes to the number of dependencies, and that's a sign that you don't need to try too hard to come up with a great engineering solution, and that doing so may very well contradict your goals for ease of maintenance (ease of change).

Avoiding the Dynamic Cast

That said, just for completeness, I'll show you a simple way to avoid the cast in these kinds of scenarios. You can do this:

class IView{
public:
    ...

    // Returns null if keyboard handling is unsupported.
    virtual IKeyboardHandler* keyboard() = 0;

    // Returns null if mouse handling is unsupported.
    virtual IMouseHandler* mouse() = 0;
};

... view types that don't need inherit from (implement) IKeyboardHandler can simply return null, e.g. Ones that do can simply return this;. This way you can find out if a view supports keyboard handling with an interface query which doesn't involve casting, and if so, handle keyboard input for that view.

Taking this technique further to a greater degree of flexibility will often have you approaching COM-style designs (which does involve casting but hides it from the client), and even further, entity-component systems (which can be very useful to know about as a game developer, but probably outside of this view context). Yet I think this is absolute overkill for your case even with the basic form, and likely to just add more burdens upfront without alleviating any later.

Yet this basic version shown above can be a useful design technique if you had, say, functions in your system which can work strictly with IKeyboardHandler, and you potentially have things other than views which might implement this keyboard handling interface.

deleted 3483 characters in body
Source Link
user204677
user204677

The interface segregation principle is focused more on completely irrelevant functionality. Here it's not so clear cut.

A blatant example of a violation of ISP is a Scrollbar interface with a setText function inherited from Widget, when a scrollbar won't even show any text. In such a case, the function may even be documented as irrelevant to callers, and to attempt to call such a functionWorking on a scrollbar may indicate a logical error.

Such blatant violations of ISP tend to be most foul, with monolithic interfaces that might have 200 functions with only 20 of them being relevant for the actual object in question. I see it often in GUI designs which are based around massive inheritance hierarchies, and oftendeleting my posts with documentation mechanisms trying to filter out the enormous amount of irrelevant derived functionality.

In your case, I think it's a bit different since given a function like this:

virtual bool handleInput(KeyEvent aKeyEvent, ...) = 0;

... it's still relevant to clients whether or not a view handles keyboard input. The fact that it doesn't is still relevant information, and worth calling the function to find out. So I don't see this as a clear violation of ISP.

You could try to split up the interface into multiple interfaces like IKeyboardHandler, but it's likely to make things harder rather than easier. It's worth noting the scope here in terms of dependencies.

A game will typically only have a handful of such views. You might have a main menu screen of sorts, splash screen, HUD, game view, maybe an in-game pie menu or something. It's a handful of views. The clients will also tend to be few in number, maybe just one broad client which is the one handling events from the operating system and calling the relevant view functionspositive answers. So it's very limited in scope/scale when it comes to the number of dependencies, and that's a sign that you don't needGoing to try too hard to come up with a great engineering solution, and that doing so may very well contradict your goals for ease of maintenance (ease of change).

Avoiding the Dynamic Cast

That said, just for completeness, I'll show you a simple way to avoid the cast in these kinds of scenarios. You can do this:

class IView{
public:
    ...

    // Returns null if keyboard handling is unsupported.
    virtual IKeyboardHandler* keyboard() = 0;

    // Returns null if mouse handling is unsupported.
    virtual IMouseHandler* mouse() = 0;
};

... view types that don't need inherit from (implement) IKeyboardHandler can simply return null, e.g. Ones that do can simply return this;. This way you can find out if a view supports keyboard handling with an interface query which doesn't involve casting, and if so, handle keyboard input for that view.

Taking this technique further to a greater degree of flexibility will often have you approaching COM-style designs (which does involve casting but hides it from the client), and even further, entity-component systems (which can be very useful to know about as a game developer, but probably outside of this view context). Yet I think this is absolute overkill for your case even with the basic form, and likely to just add more burdens upfront without alleviating any later.

Yet this basic version shown above can be a useful design technique if you had, say, functions in your system which can work strictly with IKeyboardHandler, and you potentially have things other than views which might implement this keyboard handling interface.maximum negative votes!

The interface segregation principle is focused more on completely irrelevant functionality. Here it's not so clear cut.

A blatant example of a violation of ISP is a Scrollbar interface with a setText function inherited from Widget, when a scrollbar won't even show any text. In such a case, the function may even be documented as irrelevant to callers, and to attempt to call such a function on a scrollbar may indicate a logical error.

Such blatant violations of ISP tend to be most foul, with monolithic interfaces that might have 200 functions with only 20 of them being relevant for the actual object in question. I see it often in GUI designs which are based around massive inheritance hierarchies, and often with documentation mechanisms trying to filter out the enormous amount of irrelevant derived functionality.

In your case, I think it's a bit different since given a function like this:

virtual bool handleInput(KeyEvent aKeyEvent, ...) = 0;

... it's still relevant to clients whether or not a view handles keyboard input. The fact that it doesn't is still relevant information, and worth calling the function to find out. So I don't see this as a clear violation of ISP.

You could try to split up the interface into multiple interfaces like IKeyboardHandler, but it's likely to make things harder rather than easier. It's worth noting the scope here in terms of dependencies.

A game will typically only have a handful of such views. You might have a main menu screen of sorts, splash screen, HUD, game view, maybe an in-game pie menu or something. It's a handful of views. The clients will also tend to be few in number, maybe just one broad client which is the one handling events from the operating system and calling the relevant view functions. So it's very limited in scope/scale when it comes to the number of dependencies, and that's a sign that you don't need to try too hard to come up with a great engineering solution, and that doing so may very well contradict your goals for ease of maintenance (ease of change).

Avoiding the Dynamic Cast

That said, just for completeness, I'll show you a simple way to avoid the cast in these kinds of scenarios. You can do this:

class IView{
public:
    ...

    // Returns null if keyboard handling is unsupported.
    virtual IKeyboardHandler* keyboard() = 0;

    // Returns null if mouse handling is unsupported.
    virtual IMouseHandler* mouse() = 0;
};

... view types that don't need inherit from (implement) IKeyboardHandler can simply return null, e.g. Ones that do can simply return this;. This way you can find out if a view supports keyboard handling with an interface query which doesn't involve casting, and if so, handle keyboard input for that view.

Taking this technique further to a greater degree of flexibility will often have you approaching COM-style designs (which does involve casting but hides it from the client), and even further, entity-component systems (which can be very useful to know about as a game developer, but probably outside of this view context). Yet I think this is absolute overkill for your case even with the basic form, and likely to just add more burdens upfront without alleviating any later.

Yet this basic version shown above can be a useful design technique if you had, say, functions in your system which can work strictly with IKeyboardHandler, and you potentially have things other than views which might implement this keyboard handling interface.

Working on deleting my posts with positive answers. Going to try for maximum negative votes!

added 55 characters in body
Source Link
user204677
user204677

Avoiding the DowncastDynamic Cast

That said, just for completeness, I'll show you a simple way to avoid the downcastcast in these kinds of scenarios. You can do this:

... view types that don't need inherit from (implement) IKeyboardHandler can simply return null, e.g. Ones that do can simply return this;. This way you can find out if a view supports keyboard handling with an interface query which doesn't involve a downcastcasting, and if so, handle keyboard input for that view.

Taking this technique further to a greater degree of flexibility will often have you approaching COM-style designs (which does involve casting but hides it from the client), and even further, entity-component systems (which can be very useful to know about as a game developer, but probably outside of this view context). Yet I think this is absolute overkill for your case even with the basic form, and likely to just add more burdens upfront without alleviating any later.

Avoiding the Downcast

That said, just for completeness, I'll show you a simple way to avoid the downcast in these kinds of scenarios. You can do this:

... view types that don't need inherit from (implement) IKeyboardHandler can simply return null, e.g. Ones that do can simply return this;. This way you can find out if a view supports keyboard handling with an interface query which doesn't involve a downcast, and if so, handle keyboard input for that view.

Taking this technique further to a greater degree of flexibility will often have you approaching COM-style designs, and even further, entity-component systems (which can be very useful to know about as a game developer, but probably outside of this view context). Yet I think this is absolute overkill for your case even with the basic form, and likely to just add more burdens upfront without alleviating any later.

Avoiding the Dynamic Cast

That said, just for completeness, I'll show you a simple way to avoid the cast in these kinds of scenarios. You can do this:

... view types that don't need inherit from (implement) IKeyboardHandler can simply return null, e.g. Ones that do can simply return this;. This way you can find out if a view supports keyboard handling with an interface query which doesn't involve casting, and if so, handle keyboard input for that view.

Taking this technique further to a greater degree of flexibility will often have you approaching COM-style designs (which does involve casting but hides it from the client), and even further, entity-component systems (which can be very useful to know about as a game developer, but probably outside of this view context). Yet I think this is absolute overkill for your case even with the basic form, and likely to just add more burdens upfront without alleviating any later.

added 169 characters in body
Source Link
user204677
user204677
Loading
Source Link
user204677
user204677
Loading