I am looking for a technique to have a single entry point for my interface, but where each implementation is handled differently.
Let's show an example.
I have got a couple of implementations of an Instrument-interface. Instruments ofcourse share some similarities (they make music, have something to do with notes and scales) but they are played very differently.
A Musician can play an instrument, and a gifted musician can play several instruments:
public interface Musician {
void play(Instrument instrument);
}
public class GiftedMusician implements Musician {
#Override
public void play(Instrument instrument) {
if (instrument instanceof Guitar) {
play((Guitar) instrument);
} else if (instrument instanceof Bass) {
play((Bass) instrument);
} else if (instrument instanceof Piano) {
play((Piano) instrument);
}
}
public void play(Guitar guitar) {
guitar.strumWithPick();
}
public void play(Bass bass) {
bass.pluckString();
}
public void play(Piano piano) {
piano.pressKey();
}
}
I have found a solution using instanceof but I am not sure if this is the way to go. I am looking for a design pattern or otherwise best practice to handle such a scenario.
Edit:
This example was of course very simple, let's make it a little less obvious. Because, as i said, there are many many kinds of instruments, which are played in different ways. Like a contrabass. How would I implement a Musician that plays regular- and contrabass?
public class Contrabass implements Instrument{
public void play(boolean useBow) {
if(useBow)
playWithBow();
else
pluckWithFingers();
}
}
In my opinion, you should declare the following method in Instrument:
public void play(Musician musician);
You can then implement it differently for each instrument.
For instance:
class Guitar implements Instrument {
#Override
public void play(Musician musician) {
System.out.printf("Musician %s is playing the guitar!%n", musician.getName());
strumWithPick();
}
}
... and so on.
With this example, your GiftedMusician class would make less sense, unless you decide to use composition to associate an Instrument or many to a Musician.
In the latter case, your GiftedMusician would have a constructor overload taking, say, a Collection<Instrument>, whereas your Musician would only have a constructor with a single Instrument.
For instance (with Instrument as abstract class, to add core "functionality" to play):
class Musician {
protected Collection<Instrument> instruments;
Musician(Instrument instrument) {
instruments = new HashSet<Instrument>();
if (instrument != null)
instruments.add(instrument);
}
public String getName() {
// of course
return "J. S. Bach";
}
}
class GiftedMusician extends Musician {
GiftedMusician(Instrument instrument) {
super(instrument);
}
GiftedMusician(Collection<Instrument> instruments) {
super(null);
this.instruments = new HashSet<Instrument>(instruments);
}
}
abstract class Instrument {
protected String name;
public void play(Musician musician) {
System.out.printf("Musician %s is playing %s%n", musician.getName(), name);
}
}
Edit following up question edit.
If you need to parametrize a specific playing technique into your play method, without an overload anti-pattern and returning to the instanceof long list anti-pattern, you've got all the more reason to parametrize play with a Musician.
It's the Musician who decides the technique they want to play with after all.
Once within the play body, you can then adapt the playing logic to something in the lines of musician.getCurrentTechnique().
First of all: You're right when questioning the use of instanceof. It may have some use-cases, but whenever you feel tempted to use instanceof, you should take a step back and check whether your design is really sound.
My suggestions are roughly in line with what Mena said in his answer. But from a conceptual view, I think that the direction of the dependency is a bit odd when you have to write a line like
instrument.play(musician);
instead of
musician.play(instrument);
A phrase like "an instrument can be played" IMHO suggests that the instruments are a parameter of a method, and not the object that the method is called on. They are "passive", in that sense. (One of your comments was also related to this, when you said that "the Instrument-class has an import on Musician", which doesn't seem right). But whether or not this is appropriate also depends on the real use-case. The example is very artificial and suggestive, and this may lead to suggestions for solutions that don't fit in the real world. The possible solutions for modeling this largely vary in the responsiblities, the question "Who knows what?", and how the modeled structures are intended to be used, and it's hard to give a general answer here.
However, considering that instruments can be played, it seems obvious that one could intruduce a simple method bePlayed() in the Instrument interface. This was already suggested in the other answers, leading to an implementation of the Musician interface that simply plays the instrument:
public class GiftedMusician implements Musician
{
#Override
public void play(Instrument instrument)
{
instrument.bePlayed();
}
}
One of the open issues is:
Who (and how) decides whether a musician can play the instrument?
One pragmatic solution would be to let the musician know the instrument classes that he can play:
public class GiftedMusician implements Musician
{
private final Set<Class<?>> instrumentClasses =
new LinkedHashSet<Class<?>>();
<T extends Instrument> void learn(Class<T> instrumentClass)
{
instrumentClasses.add(instrumentClass);
}
void drinkLotsOfBeer()
{
instrumentClasses.clear();
}
#Override
public void play(Instrument instrument)
{
if (instrumentClasses.contains(instrument.getClass())
{
instrument.bePlayed();
}
else
{
System.out.println("I can't play the " + instrument.getClass());
}
}
}
In your EDIT, you opened a new degree of freedom for the design space: You mentioned that the instruments can be played in different ways (like the contrabass, with bow or fingers). This suggests that it may be appropriate to introduce a PlayingTechnique class, as Mena also said in the comments.
The first shot could look like this
interface PlayingTechnique {
void applyTo(Instrument instrument);
}
But this raises two questions:
1. Which methods does the Instrument interface offer?
This question could be phrased in more natural language: What do Instruments have in common?. Intuitively, one would say: Not much. They can be played, as already shown in the bePlayed() method mentioned above. But this does not cover the different techniques, and these techniques may be highly specific for the particular class. However, you already mentioned some methods that the concrete classes could have:
Guitar#strumWithPick()
Bass#pluckString()
Piano#pressKey();
Contrabass#playWithBow();
Contrabass#pluckWithFingers()
So regarding the PlayingTechnique class, one could consider adding some generics:
interface PlayingTechnique<T extends Instrument>
{
Class<?> getInstrumentClass();
void applyTo(T instrument);
}
and have different implementations of these:
class ContrabassBowPlayingTechnique
implements PlayingTechnique<Contrabass> {
#Override
public Class<?> getInstrumentClass()
{
return Contrabass.class;
}
#Override
public void applyTo(Contrabass instrument)
{
instrument.playWithBow();
}
}
class ContrabassFingersPlayingTechnique
implements PlayingTechnique<Contrabass> {
#Override
public Class<?> getInstrumentClass()
{
return Contrabass.class;
}
#Override
public void applyTo(Contrabass instrument)
{
instrument.pluckWithFingers();
}
}
(Side note: One could consider generalizing this even further. This would roughly mean that the Instrument interface would have several sub-interfaces, like StringInstrument and KeyInstrument and WindInstrument, each offering an appropriate set of more specific methods, like
StringInstrument#playWithBow()
StringInstrument#playWithFingers()
While technically possible, this would raise questions like whether a Guitar may be played with the bow, or a Violin may be played with the fingers - but this goes beyond what can seriously be considered based on the artificial example)
The GiftedMusician class could be adjusted accordingly:
public class GiftedMusician implements Musician
{
private final Set<PlayingTechnique<?>> playingTechniques =
new LinkedHashSet<PlayingTechnique<?>>();
<T extends Instrument> void learn(PlayingTechnique<T> playingTechnique)
{
playingTechniques.add(playingTechnique);
}
void drinkLotsOfBeer()
{
playingTechniques.clear();
}
#Override
public void play(Instrument instrument)
{
for (PlayingTechnique<?> playingTechnique : playingTechniques)
{
if (playingTechnique.getInstrumentClass() == instrument.getClass())
{
// May need to cast here (but it's safe)
playingTechnique.applyTo(instrument);
return;
}
}
System.out.println("I can't play the " + instrument.getClass());
}
}
Still, there is a second open question:
2. Who decides (when and how) which PlayingTechique is applied?
In the current form, a gifted musician could learn two playing techniques for the same instrument class:
giftedMusician.learn(new ContrabassBowPlayingTechnique());
giftedMusician.learn(new ContrabassFingersPlayingTechnique());
// Which technique will he apply?
giftedMusician.play(contrabass);
But whether the decision is made by the Musician (maybe based on some "proficiency" that is associated with each technique), or from the outside, will depend on the real-world problem that you are actually trying to solve.
Add method
void play();
to the Instrument interface. Each implementation of it should be calling respective method, e.g.
public class Guitar implements Instrument {
public void play() {
strumWithPick();
}
private void strumWithPick() {
// implementation details here
}
}
Then GiftedMusician#play(Instrument) should be simplified:
public void play(Instrument instrument) {
instrument.play();
}
Add the method void play(); to your interface without any parameters. What you want to do is exhibit the behaviour of polymorphism.
So instead of using instanceof to check for each implementation, you have it in your interface as just void play();. Hence, whenever the interface is implemented, the play() method can be overriden and implemented specifically for the given class e.g. your Bass class.
It seems code examples have already been given in other answers but specifically look up the term polymorphism in the context of OOP. In particular this question has some good answers: What is polymorphism, what is it for, and how is it used?
Related
I do have a service which needs to handle two types of meal.
#Service
class MealService {
private final List<MealStrategy> strategies;
MealService(…) {
this.strategies = strategies;
}
void handle() {
var foo = …;
var bar = …;
strategies.forEach(s -> s.remove(foo, bar));
}
}
There are two strategies, ‘BurgerStrategy’ and ‘PastaStrategy’. Both implements Strategy interface with one method called remove which takes two parameters.
BurgerStrategy class retrieves meals of enum type burger from the database and iterate over them and perform some operations. Similar stuff does the PastaStrategy.
The question is, does it make sense to call it Strategy and implement it this way or not?
Also, how to handle duplications of the code in those two services, let’s say both share the same private methods. Does it make sense to create a Helper class or something?
does it make sense to call it Strategy and implement it this way or not
I think these classes ‘BurgerStrategy’ and ‘PastaStrategy’ have common behaviour. Strategy pattern is used when you want to inject one strategy and use it. However, you are iterating through all behaviors. You did not set behaviour by getting one strategy and stick with it. So, in my honour opinion, I think it is better to avoid Strategy word here.
So strategy pattern would look like this. I am sorry, I am not Java guy. Let me show via C#. But I've provided comments of how code could look in Java.
This is our abstraction of strategy:
public interface ISoundBehaviour
{
void Make();
}
and its concrete implementation:
public class DogSound : ISoundBehaviour // implements in Java
{
public void Make()
{
Console.WriteLine("Woof");
}
}
public class CatSound : ISoundBehaviour
{
public void Make()
{
Console.WriteLine("Meow");
}
}
And then we stick with one behaviour that can also be replaced:
public class Dog
{
ISoundBehaviour _soundBehaviour;
public Dog(ISoundBehaviour soundBehaviour)
{
_soundBehaviour = soundBehaviour;
}
public void Bark()
{
_soundBehaviour.Make();
}
public void SetAnotherSound(ISoundBehaviour anotherSoundBehaviour)
{
_soundBehaviour = anotherSoundBehaviour;
}
}
how to handle duplications of the code in those two services, let’s say both share the same private methods.
You can create one base, abstract class. So basic idea is to put common logic into some base common class. Then we should create abstract method in abstract class. Why? By doing this, subclasses will have particular logic for concrete case. Let me show an example.
An abstract class which has common behaviour:
public abstract class BaseMeal
{
// I am not Java guy, but if I am not mistaken, in Java,
// if you do not want method to be overriden, you shoud use `final` keyword
public void CommonBehaviourHere()
{
// put here code that can be shared among subclasses to avoid code duplication
}
public abstract void UnCommonBehaviourShouldBeImplementedBySubclass();
}
And its concrete implementations:
public class BurgerSubclass : BaseMeal // extends in Java
{
public override void UnCommonBehaviourShouldBeImplementedBySubclass()
{
throw new NotImplementedException();
}
}
public class PastaSubclass : BaseMeal // extends in Java
{
public override void UnCommonBehaviourShouldBeImplementedBySubclass()
{
throw new NotImplementedException();
}
}
I'm building a simple game in Java. I have a couple of classes, I omitted the fields that are not relevant to my problem:
public class Character {
//stores relics and artifacts
public Set<Collectable> inventory;
public void collect(Collectable collectable) {
collectable.collect(this);
}
}
public class Artifact extends Collectable {
#Override
public void collect(Character character) {
character.inventory.add(this);
}
}
public class Relic extends Collectable {
#Override
public void collect(Character character) {
character.inventory.add(this);
}
}
public class Spell extends Collectable {
#Override
public void collect(Character character) {
Wizard wizard = (Wizard) character;
wizard.spellBook.add(this);
}
}
public class Wizard extends Character {
//stores spells
public Set<Collectable> spellBook;
}
public class Warrior extends Character {
//fields and methods ommited
}
As of right now when I'm collecting a Spell, it has to go into a Wizard's spellBook. Warriors can't collect Spells, they don't have a spellBook.
If I understand correctly from an OOP POV, a Collectable has to be able to decide where it goes (inventory or spellbook) when it's collected, hence my solution above.
My problem is that I have to use typecasting in Spell.collect(Character) to be able to put the Spell into a Wizard's spellBook, because by default, spellBook is not visible on Character, and I think it shouldn't be, because then Warriors would have spellBooks aswell.
This goes against the Open-Closed principle, since if I wanted to add a Warlock, who can also collect Spells, I would have to modify Spell to try and cast it to Warlock aswell.
Could you please suggest a solution or design pattern, so that I can collect my Collectables without violating the Open-Closed princible?
This is a lot of fun thinking about this. The other answers here definitely address your issue already, but I think in the grand scheme of things you need to change your architecture to something like MVC (model view controller) or SAM (state action model). These will give you a better idea of how to make up classes, b/c right now it seems like you are trying to model your world in terms of physical objects, which is NOT what OOP is about. OOP is about the transfer of data.
With MVC, it might look like:
Model:
public class Spell extends MagicCollectable {
// attributes like damage or healing
}
public class Relic extends PhysicalCollectable {
// attributes
}
public class Wizard extends Character {
//stores spells
public Set<Collectable> spellBook;
}
public class Warrior extends Character {
//fields and methods ommited
}
Controller:
public class WizardController {
private Wizard wizard;
public void collect(MagicCollectable collectable);
}
public class WarriorController {
private Warrior warrior;
public void collect(PhysicalCollectable collectable);
}
So in your game loop you would actually be instantiating WizardController to embody your character. Also notice, like the other answers, I'm creating more specific models.
There is no reason public Set<Collectable> spellBook; shouldn't be public Set<Spell> spellBook;
Best thing to do would be to make an Interface:
interface SpellCaster{
void addSpell();
//other methods
}
and make any character that should be able to collect spells implement this interface.
Edit:
And then the collect method in Spell should look like:
#Override
public void collect(SpellCaster character) {
character.addSpell(this);
}
Although you probably should rename the method. You have two collect methods that are doing something completely different.
I find it interesting that you decided to let the collectable decide where it goes. In a real world scenario wouldn't a Character collect the collectable and for example a wizard collect the spell?
public class Wizard extends Character {
//stores spells
private Set<Spell> spellBook;
public void addSpell(Spell spell) {
spellBook.add(spell);
}
}
In short, I'd like to be able to group class instances by a superclass which does not implement a certain interface. But from the set of instances I'd like to call methods from the interface on those instances that implement that interface.
Some example code which might explain it.
class Building{
String c = "white";
Building(){
}
void printColor(){
println("The building is " + c);
}
void paint( String c ){
this.c = c;
}
void printBuildQuality(){
println("The build quality is average");
}
}
class SturdyFactoryBuilding extends Building implements Factory{
SturdyFactoryBuilding(){
super();
}
void printBuildQuality(){
println("The build quality is sturdy");
}
void printFactoryOutput(){
println("This factory makes stuff");
}
}
class ShakyFactoryBuilding extends Building implements Factory{
ShakyFactoryBuilding(){
super();
}
void printBuildQuality(){
println("The build quality is shaky");
}
void printFactoryOutput(){
println("This factory makes slightly different stuff");
}
}
public interface Factory{
public void printFactoryOutput();
}
Building building = new SturdyFactoryBuilding();
building.printBuildQuality();
building.printColor();
building.paint("bright red");
building.printColor();
building.printFactoryOutput();
Is there a way I can achieve this, perhaps by having an 'isFactory' flag in the superclass.
Thanks.
I think you'll have to make a trade-off: Either you accept some anti-pattern or you open up you Building "interface" to act as an Adapter:
class Building implements Factory{
// the other building stuff
#Override
public void printFactoryOutput(){ /* NO OP */ }
}
Then you can call printFactoryOutput on all Buildings having no effect up to this point.
Since your Factory-implementations extend Building they automatically inherit the NOOP-Implementation. But since you override it:
class ShakyFactoryBuilding extends Building implements Factory{
ShakyFactoryBuilding(){
super();
}
#Override
public void printBuildQuality(){
println("The build quality is shaky");
}
#Override
public void printFactoryOutput(){
println("This factory makes slightly different stuff");
}
}
... you have the desired result.
Drawback is of course that all Buildings do have the printFactoryOutput visible. But that's the trade-off I was talking about. If this is not acceptable, you'll have to completely reconsider your design.
To make it clear that a Building that is not a Factory shall not be called that Method on, you could throw an UnsupportedOperationException in Building, but that would force try/catch blocks everywhere in your code. You could as well return a boolean: default=false and returning true if in fact a factory ... There are plenty possibilities.
You could also change your design to use composition over inheritance.
I think you're getting the message that this is a bad idea. It violates generally accepted object oriented design principles. That said, there are several ways to go about it, some less odious than others.
Just cast it
The simplest thing to do is something like this:
if (building instanceof Factory)
((Factory)building).printFactoryOutput();
You're checking to see whether it's a Factory, then invoking the Factory-specific method after casting. It's a straightforward (and therefore easily understood) way of implementing a bad design.
Make Building aware of Factory
This has issues in that there is currently no necessary relationship between Building and Factory, but such a relationship might help you along.
class Building {
// ...
Factory adaptToFactory() {
return null;
}
}
class SturdyFactoryBuilding ... {
// ...
#Override
Factory adaptToFactory() {
return this;
}
}
Similarly for ShakyFactoryBuilding.
Then you could write
Factory f = building.adaptToFactory();
if (f != null)
f.printFactoryOutput();
More general adapter
If you're doing a lot of this kind of thing, you could make it into a pattern that you apply wherever needed. (Eclipse, for example, uses adapters all over the place.)
interface Adaptable {
<T> T adapt(Class<T> clazz);
}
class Building implements Adaptable {
// ...
#Override
<T> T adapt(Class<T> clazz) {
if (clazz.isInstance(this)) {
return clazz.cast(this);
}
return null;
}
}
Then you'd write
Factory f = building.adapt(Factory.class);
if (f != null)
f.printFactoryOutput();
There are still more places to go with this, but this is far enough for this question, I think.
I am trying to find a way to bypass the use of instanceof. I've created a class Item which has multiple subclasses like WeaponItem and BodyItem. Now I would like to make to do a call such as equip(Item) and it should determine by itself which overloaded function it should call such as equip(BodyItem).
Is there a way to bypass the use of instanceof for this case and what would you recommend? I've heard that in most cases using instanceof is bad practice and therefor I want to know what the alternatives are.
Code:
inv.equip(it); // inv = inventory object, it = Item
An example of equip function within inventory class how I preferably want it
public void equip(HelmItem it)
{
if (it != this.getHelm())
{
this.setHelm(it);
}
}
How I had it before:
public void equip(Item it)
{
if (it instanceof WeaponItem)
{
if (it != this.getWeapon())
{
this.setWeapon((WeaponItem) it);
}
} etc for all subclasses of item
}
Indeed, this could be solved with a visitor pattern.
However, it does not have to be a full-blown visitor, but a simplified variation of it. You could pass the inventory to the item and let the item do whatever it wants with it:
abstract class Item {
public abstract void equip(Inventory inv);
}
class HelmItem extends Item {
#Override
public void equip(Inventory inv) {
inv.setHelm(this);
}
}
class WeaponItem extends Item {
#Override
public void equip(Inventory inv) {
inv.setWeapon(this);
}
}
Then you can just call:
it.equip(inv)
without the instanceof operator.
Why not put the method in the Item concrete class, and it can equip itself? It's a little counter intuitive but it would solve your problem.
public class SomeConcreteItem extends Item {
public void equip(Body body) {
// Just an example.
body.getSections().get(0).equip(this);
}
}
That way, the concrete implementation knows how to equip itself and the classes that use it don't care. You can reference it by the Item superclass and provided that the Item superclass has an abstract method public void equip(Body body);, then you don't ever need to know about the concrete implementation and, therefore, no need for the instanceof operator.
A Note on Introducing a Design Pattern
You should be careful about introducing Design Patterns. People have a bad habit of leaping straight to a complicated pattern to solve a problem, when really something simpler and (in my opinion) more elegant is available.
I have an interface called Section and MapSection which extends section. I have a list of Sections and if it is a MapSection I need to do some additional processing. I can thing of two ways to handle this. I can add a boolean isAMapSection() to the Section interface but that leads to alot of isA.. if I add more types. The other way I could think of is instanceof check but my OOP senses think this is not great either.
curSection instanceof MapSection
which one of these is the right way? or is there another way?
As mentioned above by Oliver Charlesworth's comment, you could use a Visitor Design Pattern to give your code to do different actions depending on the type involved, without having to use a bunch of instanceof's or class equals.
For example, say you have two similar interfaces, Section and MapSection, where for grins will give MapSection one additional method:
interface Section {
void someMethod();
void accept(SectionVisitor visitor);
}
interface MapSection extends Section {
void additionalProcessingMethod();
}
We'll also give Section the accept(...) method to allow action by a Visitor of type SectionVisitor whose interface looks like:
interface SectionVisitor {
void visit(Section section);
void visit(MapSection mapSection);
}
The visit method will hold code that knows which methods to call depending on the type passed into it.
A very simple concrete example could look like:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class VisitorTest {
public static void main(String[] args) {
Random random = new Random();
List<Section> sectionList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Section section = random.nextBoolean() ? new ConcreteSection() : new ConcreteMapSection();
sectionList.add(section);
}
SectionVisitor visitor = new ConcreteSectionVisitor();
for (Section section : sectionList) {
section.accept(visitor);
}
}
}
interface Section {
void someMethod();
void accept(SectionVisitor visitor);
}
interface MapSection extends Section {
void additionalProcessingMethod();
}
interface SectionVisitor {
void visit(Section section);
void visit(MapSection mapSection);
}
class ConcreteSection implements Section {
#Override
public void someMethod() {
System.out.println("someMethod in ConcreteSection");
}
#Override
public void accept(SectionVisitor visitor) {
visitor.visit(this);
}
}
class ConcreteMapSection implements MapSection {
#Override
public void someMethod() {
System.out.println("someMethod in ConcreteMapSection");
}
#Override
public void additionalProcessingMethod() {
System.out.println("additionalProcessingMethod in ConcreteMapSection");
}
#Override
public void accept(SectionVisitor visitor) {
visitor.visit(this);
}
}
class ConcreteSectionVisitor implements SectionVisitor {
#Override
public void visit(Section section) {
section.someMethod();
}
#Override
public void visit(MapSection mapSection) {
mapSection.someMethod();
mapSection.additionalProcessingMethod();
}
}
Best way might be to add a method "additionalProcessing" to Section. Implement this method to do your additional processing in MapSection, and leave it blank in your other implementations
Sometimes it's fine to have an isXXX method (and the corresponding asXXX method is nice too), but it really depends on how open-ended your object hierarchy is.
For example in StAX the XMLEvent interface will have descendants that represent the different types of events that can come from an XML document. But the list of those types is closed (no-one's going to radically change the XML format any time soon) and very short (there are about 10 different types of events in the StAX API), so it's fine. These interfaces also define the primary nature of their implementations, you wouldn't realistically just tag an object with an XMLEvent interface like you do with Serializable or Iterable.
If your interface is more "behavioural" (for want of a better word), more optional (like Comparable) or too open-ended (like LayoutManager), things like the visitor or the strategy pattern may be more appropriate.
Judging just by the names Section and MapSection, your model seems to belong to the first category but really only you can make that decision. What I definitely wouldn't do is leave it to the client of the code to fool around with instanceof calls. One way or another the solution should be part of Section.