Home > Net >  How can I solve this Interface Segregation Principle Violation
How can I solve this Interface Segregation Principle Violation

Time:07-09

I'm facing a similar scenario to this issue and I was wondering if it's possible to get around a cleaner solution.

Supposing we have a party that has People on it, We have the interface:

public interface IPerson {
 void Arrive();
 void Dance();
}

And its implementations, people that are able to dance

public class PersonThatCanDance : IPerson {

 public void Arrive() {

  //Logic related to arriving
 }

 public void Dance() {

  //Logic related to dancing
 }
}

and those who aren't

 public class PersonThatCannotDance : IPerson {

  public void Arrive() {

   //Logic related to arriving
  }

  public void Dance() {
  
  }
}

Knowing this, now we have the party with 2 people

public class Party {

 private IPerson person1;
 private IPerson person2
 
 private void StartParty() {

  person1.Arrive();
  person2.Arrive();
 }

 private void StartMusic() {
 
  person1.Dance();
  person2.Dance();
 }
}

With this scenario settled, the problem comes when we want to make the party not care if the person is a person that can dance or not. The party throws the people into dancing no matter if they have functionality to do so.

From what I understand, the existence of the Dance() method in PersonThatCannotDance is a violation of ISP but making the party not care about what kind of person is preventing me from respecting the principle.

Is there a way to get around this? Thank you.

CodePudding user response:

yes you are right. it is violation of ISP.

public interface IArrive : IPerson {
 void Arrive();
 DateTime Time {get;set;}
 string Mode {get;set;}
}

public interface IDance: IPerson {
 void Dance();
 DateTime duration {get;set;}
 string Type {get;set;}
}

public interface IPerson   {
 string Name {get;set;}
 void Dress();
}

Now Implementations looks like this, people that are able to dance

public class PersonThatCanDance : IArrive,IDance {

 string Name {get; set;}

public void Dress() {

  //Logic related to arriving
 }

 public void Arrive() {

  //Logic related to arriving
 }

 public void Dance() {

  //Logic related to dancing
 }
}

and those who aren't

 public class PersonThatCannotDance : IArrive {

string Name {get; set;}

public void Dress() {

  //Logic related to arriving
 }

  public void Arrive() {

   //Logic related to arriving
  }
}

Now I hope this solution will work. please let me know if still have doubt.

CodePudding user response:

There is not enough information to determine the right design for your situation, but I can offer a design that's broadly applicable:

public interface IPerson {
    void Arrive();
}

public class PersonThatCanDance : IPerson {
    public void Arrive(Party party) {
        //Logic related to arriving
        party.AddDancers(this);
    }

    public void Dance() {
        //Logic related to dancing
    }
}

public class PersonThatCannotDance : IPerson {
    public void Arrive(Party party) {
        //Logic related to arriving
    }
}

public class Party {
    private IPerson person1;
    private IPerson person2;

    ArrayList dancers = new ArrayList();

    private void StartParty() {

        person1.Arrive(this);
        person2.Arrive(this);
    }

    public void AddDancers(PersonThatCanDance dancer) {
        dancers.Add(dancer);
    }

    private void StartMusic() {
        for (var dancer in dancers) {
            dancer.Dance();
        }
    }
}

A possibly more idiomatic alternative, is going by events.

public class PersonThatCanDance : IPerson {
    public void Arrive(Party party) {
        //Logic related to arriving
        party.OnCueMusic(this.Dance);
    }
    ...
}

public class Party {
    public delegate void Dance();
    ArrayList musicEvents = new ArrayList();

    ...

    public void OnCueMusic(Dance dance) {
        musicEvents.Add(dance);
    }

    private void StartMusic() {
        for (var musicEvent in musicEvents) {
            musicEvent();
        }
    }
}
  • Related