The abstraction you added for the second case is usually wrong
The moment a second case appears, the instinct is to factor out what the two cases share. I have done it for twenty years and I now think it is wrong more often than it is right.
Two implementations give you exactly one axis of variation, and the axis you can see is rarely the axis the third case will move along. So you build an interface shaped by an accident, and the third case arrives with a parameter that does not fit. Then you widen the interface. Then you add a flag. Six months later the abstraction has four methods, two of which throw UnsupportedOperationException for half the implementations.
What I do instead
Wait for three. Duplicate the second case. Live with it. The cost of duplicated code is visible and bounded — you can see both copies and change both. The cost of a wrong abstraction is invisible and unbounded, because every future case has to be bent to fit it.
When the third case arrives, the shared shape is usually obvious and usually different from what you would have guessed at two.
The exception
This does not apply to things with a genuine external contract — a wire format, a database schema, a published API. There the abstraction is not your guess about future variation, it is a description of something that already exists. Factor those out immediately.
Why it matters more than it sounds
Almost every legacy codebase I have been handed is not badly written. It is over-abstracted by people who were trying to be responsible. The layers were added early, for good reasons, against a future that arrived in a different shape. Removing them is harder than adding them was — that asymmetry is the whole argument.