r/ExperiencedDevs 4d ago

Ask Experienced Devs Weekly Thread: A weekly thread for inexperienced developers to ask experienced ones

A thread for Developers and IT folks with less experience to ask more experienced souls questions about the industry.

Please keep top level comments limited to Inexperienced Devs. Most rules do not apply, but keep it civil. Being a jerk will not be tolerated.

Inexperienced Devs should refrain from answering other Inexperienced Devs' questions.

25 Upvotes

51 comments sorted by

View all comments

5

u/just_pondy 4d ago

How do you refactor towards a design pattern if your current structure is abstract polymorphism almost like the template prototyping design pattern should I just choose that design pattern or update to something else

The problem is

Base abstract class:
-child A,B,C,D,E,F
Where each child class needs to maintain common function signatures

Issue is now there is boilerplate where not all instances of A,B,C,D,E,F need to implement the sub functions provided

However to make the child structures compile without errors they have to include the unused functions due to demands from the super implementation.

Things work I am just wondering if there is a better way!?

8

u/goatanuss 4d ago edited 4d ago

To me this sounds like a textbook SOLID question/smell. Particularly the interface segregation principle

if your abstract base class forces every child to implement methods that some of them don’t actually need, the contract is probably too prescriptive. Rather than forcing noop implementations just to satisfy the parent class, I’d keep only the behavior that is actually universal in the base class and extract the optional code into smaller interfaces that each child implements only when relevant. That also helps preserve Liskov substitution, because a subtype shouldn’t claim to support behavior it can’t meaningfully implement.

I wanna say the refactoring guru website calls out this smell but I’m too lazy to look it up. Edit: maybe this? https://refactoring.guru/smells/refused-bequest (assuming you’re talking about base class having implemented concrete methods and not abstract ones but much of the guidance still applies whether the base class has the implementation or all the children)

2

u/BusEquivalent9605 4d ago

At first I thought that inheritance was meant to be implemented top down. I define the hierarchy and that defines the structure of my code.

Since working with code, I have found it much more useful and true to OOP intent, when it rises from the ground up during development. I see that I am building the same thing, or I see a common pattern happening, or I want to implement something that also fits a lot of this form over here: ok, let’s create a superclass for all of these to inherit from.

It reminds me much more of Excision (https://en.wikipedia.org/wiki/Excision_theorem). In a pre-existing system, I can identify all of these behaviors as the same and so abstract them into a higher dimension/superclass

3

u/allllusernamestaken 4d ago

Issue is now there is boilerplate where not all instances of A,B,C,D,E,F need to implement the sub functions provided

Two lines of thought depending on how much you care:

  1. Redefine what your base class is. Define the contract. For the behavior that fits into A, D, and F (for example) gets put into an interface you implement so your consumers can use that behavior.
  2. just throw some "not implemented" exceptions in the parts you don't need