Is there a good way ECS for creating variants of a behaviour like in Java interfaces?

In Java, there are interfaces – I’m not clear on the details (I don’t use Java) but from what I’ve learned, they seem to be "classes for classes": a way to effectively make individual classes "instances" of one overarching class. For example, a "Cup" interface could be implemented by a "Mug" class, a "Glass" class, a "Goblet" class etc. As long as they have the same I/O methods such as fill(), empty() or drink(), they can be used interchangeably.

In languages with duck typing, interfaces are not needed – the language allows for classes to be used interchangeably as long as no invalid properties of methods are referenced. This is another valid was of going about things in OOP. This is how I usually go about things.

My question: how can I create varied behaviour in an ECS if components are data-only? I like to think in terms of first-class functions, but that seems to be taboo since components are not supposed to hold behaviour.

Option 1, have a massive switch or if/else chain in my System:

For example, if I have an AI component with several different behaviours, I could use an integer to define which type of AI to use for that particular entity. It seems a bit convoluted and inelegant.

Option 2, have a separate Component and matching System for each behaviour:

This would be neater in each individual System but as a whole, the program would be a mess. This wouldn’t work because of the large amounts of variation such as hundreds of different guns in a shooter game.

Option 3, use a flyweight-like data structure independent of the Component:

This would mean storing all of the different behaviours elsewhere, and storing a key that a System can use to access the behaviour. This is basically a fancy version of the switch option above, but it seems neater as there wouldn’t be a massive dump of code in the System.

Option 4, creating a complex way of encoding a description of the desired behaviour which the System can interpret:

This seems to be the most overkill of the lot. Unless I have to, or there are significant advantages, I’m trying to stay away from this.

If there’s no other way, I’ll just adopt the methodology of first-class functions as I usually do and just ignore any guidelines about ECS I’ve heard, just for this one case. The problem is, it probably won’t just be one case in the future.

Have I missed any other good options? Is there an industry standard or recommendation? If not, what considerations should I make about which option to choose?