How do I avoid breaking the Liskov substitution principle with a class that implements multiple interfaces?












22















Given the following class:



class Example implements Interface1, Interface2{
...
}


When I instantiate the class using interface1:



Interface1 example = new Example();


Then I can call only the Interface1 methods, and not the Interface2 methods, unless I cast:



((Interface2) example).someInterface2Method();


Of course, to make this runtime safe, I should also wrap this with an instanceof check:



if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}


I'm aware that I could have a wrapper interface that extends both interfaces, but then I could end up with multiple interfaces to cater for all the possible permutations of interfaces that can be implemented by the same class. The Interfaces in question do not naturally extend one another so inheritance also seems wrong.



Does the instanceof / cast approach break LSP as I am interrogating the runtime instance to determine its implementations? Whichever implementation I use seems to have some side-effect either in bad design or usage.










share|improve this question




















  • 19





    I wouldn't add the check. If I had to have both interfaces in play in a single scope I'd make the compile time type Example, not Interface1.

    – duffymo
    2 days ago






  • 1





    You definitely don't need to cast in this situation. It should always be a last resort. Probably more than 90% of casts are simply a result of bad design.

    – Michael
    2 days ago






  • 9





    create a third interface which extends those 2 you've mentioned and use the former throughout your code. or use generics to be more forgiving: public <T extends Interfac1 & Interface2> void doSomething(T t)

    – Lino
    2 days ago








  • 8





    Can't you use Example example = new Example();?

    – Andy Turner
    2 days ago






  • 2





    Given that casts are a reasonable feature of the Java language, we can't answer these questions without knowing the purpose of the class and interfaces and why you want to cast.

    – Matt Timmermans
    2 days ago
















22















Given the following class:



class Example implements Interface1, Interface2{
...
}


When I instantiate the class using interface1:



Interface1 example = new Example();


Then I can call only the Interface1 methods, and not the Interface2 methods, unless I cast:



((Interface2) example).someInterface2Method();


Of course, to make this runtime safe, I should also wrap this with an instanceof check:



if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}


I'm aware that I could have a wrapper interface that extends both interfaces, but then I could end up with multiple interfaces to cater for all the possible permutations of interfaces that can be implemented by the same class. The Interfaces in question do not naturally extend one another so inheritance also seems wrong.



Does the instanceof / cast approach break LSP as I am interrogating the runtime instance to determine its implementations? Whichever implementation I use seems to have some side-effect either in bad design or usage.










share|improve this question




















  • 19





    I wouldn't add the check. If I had to have both interfaces in play in a single scope I'd make the compile time type Example, not Interface1.

    – duffymo
    2 days ago






  • 1





    You definitely don't need to cast in this situation. It should always be a last resort. Probably more than 90% of casts are simply a result of bad design.

    – Michael
    2 days ago






  • 9





    create a third interface which extends those 2 you've mentioned and use the former throughout your code. or use generics to be more forgiving: public <T extends Interfac1 & Interface2> void doSomething(T t)

    – Lino
    2 days ago








  • 8





    Can't you use Example example = new Example();?

    – Andy Turner
    2 days ago






  • 2





    Given that casts are a reasonable feature of the Java language, we can't answer these questions without knowing the purpose of the class and interfaces and why you want to cast.

    – Matt Timmermans
    2 days ago














22












22








22


4






Given the following class:



class Example implements Interface1, Interface2{
...
}


When I instantiate the class using interface1:



Interface1 example = new Example();


Then I can call only the Interface1 methods, and not the Interface2 methods, unless I cast:



((Interface2) example).someInterface2Method();


Of course, to make this runtime safe, I should also wrap this with an instanceof check:



if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}


I'm aware that I could have a wrapper interface that extends both interfaces, but then I could end up with multiple interfaces to cater for all the possible permutations of interfaces that can be implemented by the same class. The Interfaces in question do not naturally extend one another so inheritance also seems wrong.



Does the instanceof / cast approach break LSP as I am interrogating the runtime instance to determine its implementations? Whichever implementation I use seems to have some side-effect either in bad design or usage.










share|improve this question
















Given the following class:



class Example implements Interface1, Interface2{
...
}


When I instantiate the class using interface1:



Interface1 example = new Example();


Then I can call only the Interface1 methods, and not the Interface2 methods, unless I cast:



((Interface2) example).someInterface2Method();


Of course, to make this runtime safe, I should also wrap this with an instanceof check:



if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}


I'm aware that I could have a wrapper interface that extends both interfaces, but then I could end up with multiple interfaces to cater for all the possible permutations of interfaces that can be implemented by the same class. The Interfaces in question do not naturally extend one another so inheritance also seems wrong.



Does the instanceof / cast approach break LSP as I am interrogating the runtime instance to determine its implementations? Whichever implementation I use seems to have some side-effect either in bad design or usage.







java lsp






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday









Peter Mortensen

13.5k1984111




13.5k1984111










asked 2 days ago









jmljml

1375




1375








  • 19





    I wouldn't add the check. If I had to have both interfaces in play in a single scope I'd make the compile time type Example, not Interface1.

    – duffymo
    2 days ago






  • 1





    You definitely don't need to cast in this situation. It should always be a last resort. Probably more than 90% of casts are simply a result of bad design.

    – Michael
    2 days ago






  • 9





    create a third interface which extends those 2 you've mentioned and use the former throughout your code. or use generics to be more forgiving: public <T extends Interfac1 & Interface2> void doSomething(T t)

    – Lino
    2 days ago








  • 8





    Can't you use Example example = new Example();?

    – Andy Turner
    2 days ago






  • 2





    Given that casts are a reasonable feature of the Java language, we can't answer these questions without knowing the purpose of the class and interfaces and why you want to cast.

    – Matt Timmermans
    2 days ago














  • 19





    I wouldn't add the check. If I had to have both interfaces in play in a single scope I'd make the compile time type Example, not Interface1.

    – duffymo
    2 days ago






  • 1





    You definitely don't need to cast in this situation. It should always be a last resort. Probably more than 90% of casts are simply a result of bad design.

    – Michael
    2 days ago






  • 9





    create a third interface which extends those 2 you've mentioned and use the former throughout your code. or use generics to be more forgiving: public <T extends Interfac1 & Interface2> void doSomething(T t)

    – Lino
    2 days ago








  • 8





    Can't you use Example example = new Example();?

    – Andy Turner
    2 days ago






  • 2





    Given that casts are a reasonable feature of the Java language, we can't answer these questions without knowing the purpose of the class and interfaces and why you want to cast.

    – Matt Timmermans
    2 days ago








19




19





I wouldn't add the check. If I had to have both interfaces in play in a single scope I'd make the compile time type Example, not Interface1.

– duffymo
2 days ago





I wouldn't add the check. If I had to have both interfaces in play in a single scope I'd make the compile time type Example, not Interface1.

– duffymo
2 days ago




1




1





You definitely don't need to cast in this situation. It should always be a last resort. Probably more than 90% of casts are simply a result of bad design.

– Michael
2 days ago





You definitely don't need to cast in this situation. It should always be a last resort. Probably more than 90% of casts are simply a result of bad design.

– Michael
2 days ago




9




9





create a third interface which extends those 2 you've mentioned and use the former throughout your code. or use generics to be more forgiving: public <T extends Interfac1 & Interface2> void doSomething(T t)

– Lino
2 days ago







create a third interface which extends those 2 you've mentioned and use the former throughout your code. or use generics to be more forgiving: public <T extends Interfac1 & Interface2> void doSomething(T t)

– Lino
2 days ago






8




8





Can't you use Example example = new Example();?

– Andy Turner
2 days ago





Can't you use Example example = new Example();?

– Andy Turner
2 days ago




2




2





Given that casts are a reasonable feature of the Java language, we can't answer these questions without knowing the purpose of the class and interfaces and why you want to cast.

– Matt Timmermans
2 days ago





Given that casts are a reasonable feature of the Java language, we can't answer these questions without knowing the purpose of the class and interfaces and why you want to cast.

– Matt Timmermans
2 days ago












8 Answers
8






active

oldest

votes


















20















I'm aware that I could have a wrapper interface that extends both
interfaces, but then I could end up with multiple interfaces to cater
for all the possible permutations of interfaces that can be
implemented by the same class




I suspect that if you're finding that lots of your classes implement different combinations of interfaces then either: your concrete classes are doing too much; or (less likely) your interfaces are too small and too specialised, to the point of being useless individually.



If you have good reason for some code to require something that is both a Interface1 and a Interface2 then absolutely go ahead and make a combined version that extends both. If you struggle to think of an appropriate name for this (no, not FooAndBar) then that's an indicator that your design is wrong.



Absolutely do not rely on casting anything. It should only be used as a last resort and usually only for very specific problems (e.g. serialization).



My favourite and most-used design pattern is the decorator pattern as such most of my classes will only ever implement one interface (except for more generic interfaces such as Comparable). I would say that if your classes are frequently/always implementing more than one interface then that's a code smell.





If you're instantiating the object and using it within the same scope then you should just be writing



Example example = new Example();


Just so it's clear (I'm not sure if this is what you were suggesting), under no circumstances should you ever be writing anything like this:



Interface1 example = new Example();
if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}





share|improve this answer


























  • It is an interesting point you make when you say "to the point of being useless individually" - Interface2 in this example actually refers to an interface I have called HasParameters, which has methods getParams() and setParams() as not all implementations of Interface1 actually need to work with params. I was attempting to not break the Interface Segregation Principle, by having lots of implementations with empty getParams() and setParams() methods but like you say, Interface2 is pretty useless on its own...

    – jml
    2 days ago








  • 2





    @jml then maybe a specification of Interface1 with your said methods would be better (interface Interface2 extends Interface1 { /* get and set params */ }

    – Lino
    2 days ago






  • 2





    @jml Then what Lino suggests is probably what you want. Request and ParametizedRequest are better than Request and HasParameters.

    – Michael
    2 days ago






  • 3





    @jml HasParameters doesn't feel like an interface, but an attribute. Maybe in reality what you need to do is add the methods to Request, like hasParameters(), getParameters() and setParameters(). With Java 8 you can even have those default to false, emptyList() and throw OperationNotSupportedException respectively if you don't want to have to implement them all the time. Java's Collection classes do this all the time.

    – jbx
    2 days ago








  • 1





    With Java 8 you could include your getParams() and setParams() in Interface1 with default do-nothing implementations, like public default void setParams(Params p) {} and public default Params getParams() { return null; }

    – Stephen P
    2 days ago



















19














Your class can implement multiple interfaces fine, and it is not breaking any OOP principles. On the contrary, it is following the interface segregation principle.



It is confusing why would you have a situation where something of type Interface1 is expected to provide someInterface2Method(). That is where your design is wrong.



Think about it in a slightly different way: Imagine you have another method, void method1(Interface1 interface1). It can't expect interface1 to also be an instance of Interface2. If it was the case, the type of the argument should have been different. The example you have shown is precisely this, having a variable of type Interface1 but expecting it to also be of type Interface2.



If you want to be able to call both methods, you should have the type of your variable example set to Example. That way you avoid the instanceof and type casting altogether.



If your two interfaces Interface1 and Interface2 are not that loosely coupled, and you will often need to call methods from both, maybe separating the interfaces wasn't such a good idea, or maybe you want to have another interface which extends both.



In general (although not always), instanceof checks and type casts often indicate some OO design flaw. Sometimes the design would fit for the rest of the program, but you would have a small case where it is simpler to type cast rather than refactor everything. But if possible you should always strive to avoid it at first, as part of your design.






share|improve this answer

































    9














    You have two different options (I bet there are a lot more).



    The first is to create your own interface which extends the other two:



    interface Interface3 extends Interface1, Interface2 {}


    And then use that throughout your code:



    public void doSomething(Interface3 interface3){
    ...
    }


    The other way (and in my opinion the better one) is to use generics per method:



    public <T extends Interface1 & Interface2> void doSomething(T t){
    ...
    }


    The latter option is in fact less restricted than the former, because the generic type T gets dynamically inferred and thus leads to less coupling (a class doesn't have to implement a specific grouping interface, like the first example).






    share|improve this answer





















    • 1





      "And then use that throughout your code" The significant downside to this is that you have to make Example (and any other classes) implement this class.

      – Andy Turner
      2 days ago











    • @Andy I agree and that's why the second approach is more flexible and may probably be preferred

      – Lino
      2 days ago






    • 5





      It's worth stating your preferred option first; or, at the very least, stating "My preferred way" or similar, which is a much stronger endorsement than "the other way".

      – Andy Turner
      2 days ago






    • 4





      While you are providing correct technical solutions to the issue, be wary of implementing workarounds when the underlying issue is an architecture one. You may find yourself with even more issues in the end stemming from an incorrect design.

      – Vincent Savard
      2 days ago





















    5














    Your example does not break LSP, but it seems to break SRP. If you encounter such case where you need to cast an object to its 2nd interface, the method that contains such code can be considered busy.



    Implementing 2 (or more) interfaces in a class is fine. In deciding which interface to use as its data type depends entirely on the context of the code that will use it.



    Casting is fine, especially when changing context.



    class Payment implements Expirable, Limited {
    /* ... */
    }

    class PaymentProcessor {
    // Using payment here because i'm working with payments.
    public void process(Payment payment) {
    boolean expired = expirationChecker.check(payment);
    boolean pastLimit = limitChecker.check(payment);

    if (!expired && !pastLimit) {
    acceptPayment(payment);
    }
    }
    }

    class ExpirationChecker {
    // This the `Expirable` world, so i'm using Expirable here
    public boolean check(Expirable expirable) {
    // code
    }
    }

    class LimitChecker {
    // This class is about checking limits, thats why im using `Limited` here
    public boolean check(Limited limited) {
    // code
    }
    }





    share|improve this answer


























    • LSV? Don't you mean LSP?

      – Peter Mortensen
      yesterday











    • That was certainly a typo, sorry for that.

      – KaNa0011
      yesterday



















    4














    The core issue



    Slightly tweaking your example so I can address the core issue:



    public void DoTheThing(Interface1 example)
    {
    if (example instanceof Interface2)
    {
    ((Interface2) example).someInterface2Method();
    }
    }


    So you defined the method DoTheThing(Interface1 example). This is basically saying "to do the thing, I need an Interface1 object".



    But then, in your method body, it appears that you actually need an Interface2 object. Then why didn't you ask for one in your method parameters? Quite obviously, you should've been asking for an Interface2



    What you're doing here is assuming that whatever Interface1 object you get will also be an Interface2 object. This is not something you can rely on. You might have some classes which implement both interfaces, but you might as well have some classes which only implement one and not the other.



    There is no inherent requirement whereby Interface1 and Interface2 need to both be implemented on the same object. You can't know (nor rely on the assumption) that this is the case.



    Unless you define the inherent requirement and apply it.



    interface InterfaceBoth extends Interface1, Interface2 {}

    public void DoTheThing(InterfaceBoth example)
    {
    example.someInterface2Method();
    }


    In this case, you've required InterfaceBoth object to both implement Interface1 and Interface2. So whenever you ask for an InterfaceBoth object, you can be sure to get an object which implements both Interface1 and Interface2, and thus you can use methods from either interface without even needing to cast or check the type.



    You (and the compiler) know that this method will always be available, and there's no chance of this not working.



    Note: You could've used Example instead of creating the InterfaceBoth interface, but then you would only be able to use objects of type Example and not any other class which would implement both interfaces. I assume you're interested in handling any class which implements both interfaces, not just Example.



    Deconstructing the issue further.



    Look at this code:



    ICarrot myObject = new Superman();


    If you assume this code compiles, what can you tell me about the Superman class? That it clearly implements the ICarrot interface. That is all you can tell me. You have no idea whether Superman implements the IShovel interface or not.



    So if I try to do this:



    myObject.SomeMethodThatIsFromSupermanButNotFromICarrot();


    or this:



    myObject.SomeMethodThatIsFromIShovelButNotFromICarrot();


    Should you be surprised if I told you this code compiles? You should, because this code doesn't compile.



    You may say "but I know that it's a Superman object which has this method!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman variable.



    You may say "but I know that it's a Superman object which implements the IShovel interface!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman or IShovel variable.



    Knowing this, let's look back at your code.



    Interface1 example = new Example();


    All you've said is that you have an Interface1 variable.



    if (example instanceof Interface2) {
    ((Interface2) example).someInterface2Method();
    }


    It makes no sense for you to assume that this Interface1 object also happens to implement a second unrelated interface. Even if this code works on a technical level, it is a sign of bad design, the developer is expecting some inherent correlation between two interfaces without actually having created this correlation.



    You may say "but I know I'm putting an Example object in, the compiler should know that too!" but you'd be missing the point that if this were a method parameter, you would have no way of knowing what the callers of your method are sending.



    public void DoTheThing(Interface1 example)
    {
    if (example instanceof Interface2)
    {
    ((Interface2) example).someInterface2Method();
    }
    }


    When other callers call this method, the compiler is only going to stop them if the passed object does not implement Interface1. The compiler is not going to stop someone from passing an object of a class which implements Interface1 but does not implement Interface2.






    share|improve this answer


























    • The first ~50% of your answer is explaining something that the OP already understands in a very long-winded way. "I'm aware that I could have a wrapper interface that extends both interfaces"

      – Michael
      yesterday













    • @Michael: That only applies to the small "Unless you define..." paragraph, not "The core issue". That second paragraph isn't just added to offer a solution, but also to explain how it ideologically differs from OP's initial situation, to further clarify why OP's implicit expectations are not acknowledged by the compiler. Understanding you can do it (which is what OP does know, you're right about that) is not the same as understanding why you should do it and why the compiler expects you to and refuses to otherwise accept the code.

      – Flater
      yesterday





















    1














    Usually, many, client-specific interfaces are fine, and somewhat part of the Interface segregation principle (the "I" in SOLID). Some more specific points, on a technical level, have already been mentioned in other answers.



    Particularly that you can go too far with this segregation, by having a class like



    class Person implements FirstNameProvider, LastNameProvider, AgeProvider ... {
    @Override String getFirstName() {...}
    @Override String getLastName() {...}
    @Override int getAge() {...}
    ...
    }


    Or, conversely, that you have an implementing class that is too powerful, as in



    class Application implements DatabaseReader, DataProcessor, UserInteraction, Visualizer {
    ...
    }




    I think that the main point in the Interface Segregation Principle is that the interfaces should be client-specific. They should basically "summarize" the functions that are required by a certain client, for a certain task.



    To put it that way: The issue is to strike the right balance between the extremes that I sketched above. When I'm trying to figure out interfaces and their relationships (mutually, and in terms of the classes that implement them), I always try to take a step back and ask myself, in an intentionally naïve way: Who is going to receive what, and what is he going to do with it?



    Regarding your example: When all your clients always need the functionality of Interface1 and Interface2 at the same time, then you should consider either defining an



    interface Combined extends Interface1, Interface2 { }


    or not have different interfaces in the first place. On the other hand, when the functionalities are completely distinct and unrelated and never used together, then you should wonder why the single class is implementing them at the same time.



    At this point, one could refer to another principle, namely Composition over inheritance. Although it is not classically related to implementing multiple interfaces, composition can also be favorable in this case. For example, you could change your class to not implement the interfaces directly, but only provide instances that implement them:



    class Example {
    Interface1 getInterface1() { ... }
    Interface2 getInterface2() { ... }
    }


    It looks a bit odd in this Example (sic!), but depending on the complexity of the implementation of Interface1 and Interface2, it can really make sense to keep them separated.





    Edited in response to the comment:



    The intention here is not to pass the concrete class Example to methods that need both interfaces. A case where this could make sense is rather when a class combines the functionalities of both interfaces, but does not do so by directly implementing them at the same time. It's hard to make up an example that does not look too contrived, but something like this might bring the idea across:



    interface DatabaseReader { String read(); }
    interface DatabaseWriter { void write(String s); }

    class Database {
    DatabaseConnection connection = create();
    DatabaseReader reader = createReader(connection);
    DatabaseReader writer = createWriter(connection);

    DatabaseReader getReader() { return reader; }
    DatabaseReader getWriter() { return writer; }
    }


    The client will still rely on the interfaces. Methods like



    void create(DatabaseWriter writer) { ... }
    void read (DatabaseReader reader) { ... }
    void update(DatabaseReader reader, DatabaseWriter writer) { ... }


    could then be called with



    create(database.getWriter());
    read (database.getReader());
    update(database.getReader(), database.getWriter());


    respectively.






    share|improve this answer


























    • This is the correct answer. The interface is built for the contract that the client code needs fulfilled. If the client code reasonably expects to be able to call someInterface1Method AND someInterface2Method, then that is a new contract. From wikipedia on ISP: "no client should be forced to depend on methods it does not use." and "clients will only have to know about the methods that are of interest to them."

      – Xtros
      2 days ago













    • I'm not sure I agree with the last point. If you've decided that you can't conceptually make an interface such as Combined because the two interfaces are unrelated then dumping the two objects into one compositional object isn't any better. If they're conceptually unrelated, the consuming method(s) should just take two parameters.

      – Michael
      yesterday













    • @Michael I hesitated with the last point, because it might look odd or cause misunderstandings. To be clear: Did you understand this like the Example-object should be passed to a "consuming" method that needs both interfaces? This was not was I meant. (If it could be understood this way, I'd try to make this clearer...)

      – Marco13
      12 hours ago











    • Yeah, that kind of thing. What else would you use it for?

      – Michael
      11 hours ago











    • @Michael I added an 'edit'. If you think that this is toooo far fetched or contrived, I'd rather omit the (originally) last paragraph and the 'edit'...

      – Marco13
      4 hours ago



















    0














    The problem you describe often comes about through over-zealous application of the Interface Segregation Principle, encouraged by languages' inability to specify that members of one interface should, by default, be chained to static methods which could implement sensible behaviors.



    Consider, for example, a basic sequence/enumeration interface and the following behaviors:




    1. Produce an enumerator which can read out the objects if no other iterator has yet been created.


    2. Produce an enumerator which can read out the objects even if another iterator has already been created and used.


    3. Report how many items are in the sequence


    4. Report the value of the Nth item in the sequence


    5. Copy a range of items from the object into an array of that type.


    6. Yield a reference to an immutable object that can accommodate the above operations efficiently with contents that are guaranteed never to change.



    I would suggest that such abilities should be part of the basic sequence/enumeration interface, along with a method/property to indicate which of the above operations are meaningfully supported. Some kinds of single-shot on-demand enumerators (e.g. an infinite truly-random sequence generator) might not be able to support any of those functions, but segregating such functions into separate interfaces will make it much harder to produce efficient wrappers for many kinds of operations.



    One could produce a wrapper class that would accommodate all of the above operations, though not necessarily efficiently, on any finite sequence which supports the first ability. If, however, the class is being used to wrap an object that already supports some of those abilities (e.g. access the Nth item), having the wrapper use the underlying behaviors could be much more efficient than having it do everything via the second function above (e.g. creating a new enumerator, and using that to iteratively read and ignore items from the sequence until the desired one is reached).



    Having all objects that produce any kind of sequence support an interface that includes all of the above, along with an indication of what abilities are supported, would be cleaner than trying to have different interfaces for different subsets of abilities, and requiring that wrapper classes make explicit provision for any combinations they want to expose to their clients.






    share|improve this answer































      0














      With the help of various posts and comments on this page, a solution has been produced, which I feel is correct for my scenario.



      The following shows the iterative changes to the solution to meet SOLID principles.



      Requirement



      To produce the response for a web service, key + object pairs are added to a response object. There are lots of different key + object pairs that need to be added, each of which may have unique processing required to transform the data from the source to the format required in the response.



      From this it is clear that whilst the different key / value pairs may have different processing requirements to transform the source data to the target response object, they all have a common goal of adding an object to the response object.



      Therefore, the following interface was produced in solution iteration 1:



      Solution Iteration 1



      ResponseObjectProvider<T, S> {
      void addObject(T targetObject, S sourceObject, String targetKey);
      }


      Any developer that needs to add an object to the response can now do so using an existing implementation that matches their requirement, or add a new implementation given a new scenario



      This is great as we have a common interface which acts as a contract for this common practise of adding response objects



      However, one scenario requires that the target object should be taken from the source object given a particular key, "identifier".



      There are options here, the first is to add an implementation of the existing interface as follows:



      public class GetIdentifierResponseObjectProvider<T extends Map, S extends Map> implements ResponseObjectProvider<T, S> {
      public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
      targetObject.put(targetKey, sourceObject.get("identifier"));
      }
      }


      This works, however this scenario could be required for other source object keys ("startDate", "endDate" etc...) so this implementation should be made more generic to allow for reuse in this scenario.



      Additionally, other implementations may require more context information to perform the addObject operation... So a new generic type should be added to cater for this



      Solution Iteration 2



      ResponseObjectProvider<T, S, U> {
      void addObject(T targetObject, S sourceObject, String targetKey);
      void setParams(U params);
      U getParams();
      }


      This interface caters for both usage scenarios; the implementations that require additional params to perform the addObject operation and the implementations that do not



      However, considering the latter of the usage scenarios, the implementations that do not require additional parameters will break the SOLID Interface Segregation Principle as these implementations will override getParams and setParams methods but not implement them. e.g:



      public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S, U> {
      public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
      targetObject.put(targetKey, sourceObject.get(U));
      }

      public void setParams(U params) {
      //unimplemented method
      }

      U getParams() {
      //unimplemented method
      }

      }


      Solution Iteration 3



      To fix the Interface Segregation issue, the getParams and setParams interface methods were moved into a new Interface:



      public interface ParametersProvider<T> {
      void setParams(T params);
      T getParams();
      }


      The implementations that require parameters can now implement the ParametersProvider interface:



      public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S>, ParametersProvider<U>

      private String params;
      public void setParams(U params) {
      this.params = params;
      }

      public U getParams() {
      return this.params;
      }

      public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
      targetObject.put(targetKey, sourceObject.get(params));
      }
      }


      This solves the Interface Segregation issue but causes two more issues... If the calling client wants to program to an interface, i.e:



      ResponseObjectProvider responseObjectProvider = new  GetObjectBySourceKeyResponseObjectProvider<>();


      Then the addObject method will be available to the instance, but NOT the getParams and setParams methods of the ParametersProvider interface... To call these a cast is required, and to be safe an instanceof check should also be performed:



      if(responseObjectProvider instanceof ParametersProvider) {
      ((ParametersProvider)responseObjectProvider).setParams("identifier");
      }


      Not only is this undesirable it also breaks the Liskov Substitution Principle - "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program"



      i.e. if we replaced an implementation of ResponseObjectProvider that also implements ParametersProvider, with an implementation that does not implement ParametersProvider then this could alter the some of the desirable properties of the program... Additionally, the client needs to be aware of which implementation is in use to call the correct methods



      An additional problem is the usage for calling clients. If the calling client wanted to use an instance that implements both interfaces to perform addObject multiple times, the setParams method would need to be called before addObject... This could cause avoidable bugs if care is not taken when calling.



      Solution Iteration 4 - Final Solution



      The interfaces produced from Solution Iteration 3 solve all of the currently known usage requirements, with some flexibility provided by generics for implementation using different types. However, this solution breaks the Liskov Substitution Principle and has a non-obvious usage of setParams for the calling client



      The solution is to have two separate interfaces, ParameterisedResponseObjectProvider and ResponseObjectProvider.



      This allows the client to program to an interface, and would select the appropriate interface depending on whether the objects being added to the response require additional parameters or not



      The new interface was first implemented as an extension of ResponseObjectProvider:



      public interface ParameterisedResponseObjectProvider<T,S,U> extends ResponseObjectProvider<T, S> {
      void setParams(U params);
      U getParams();
      }


      However, this still had the usage issue, where the calling client would first need to call setParams before calling addObject and also make the code less readable.



      So the final solution has two separate interfaces defined as follows:



      public interface ResponseObjectProvider<T, S> {
      void addObject(T targetObject, S sourceObject, String targetKey);
      }


      public interface ParameterisedResponseObjectProvider<T,S,U> {
      void addObject(T targetObject, S sourceObject, String targetKey, U params);
      }


      This solution solves the breaches of Interface Segregation and Liskov Substitution principles and also improves the usage for calling clients and improves the readability of the code.



      It does mean that the client needs to be aware of the different interfaces, but since the contracts are different this seems to be a justified decision especially when considering all the issues that the solution has avoided.






      share|improve this answer























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54184354%2fhow-do-i-avoid-breaking-the-liskov-substitution-principle-with-a-class-that-impl%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        8 Answers
        8






        active

        oldest

        votes








        8 Answers
        8






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        20















        I'm aware that I could have a wrapper interface that extends both
        interfaces, but then I could end up with multiple interfaces to cater
        for all the possible permutations of interfaces that can be
        implemented by the same class




        I suspect that if you're finding that lots of your classes implement different combinations of interfaces then either: your concrete classes are doing too much; or (less likely) your interfaces are too small and too specialised, to the point of being useless individually.



        If you have good reason for some code to require something that is both a Interface1 and a Interface2 then absolutely go ahead and make a combined version that extends both. If you struggle to think of an appropriate name for this (no, not FooAndBar) then that's an indicator that your design is wrong.



        Absolutely do not rely on casting anything. It should only be used as a last resort and usually only for very specific problems (e.g. serialization).



        My favourite and most-used design pattern is the decorator pattern as such most of my classes will only ever implement one interface (except for more generic interfaces such as Comparable). I would say that if your classes are frequently/always implementing more than one interface then that's a code smell.





        If you're instantiating the object and using it within the same scope then you should just be writing



        Example example = new Example();


        Just so it's clear (I'm not sure if this is what you were suggesting), under no circumstances should you ever be writing anything like this:



        Interface1 example = new Example();
        if (example instanceof Interface2) {
        ((Interface2) example).someInterface2Method();
        }





        share|improve this answer


























        • It is an interesting point you make when you say "to the point of being useless individually" - Interface2 in this example actually refers to an interface I have called HasParameters, which has methods getParams() and setParams() as not all implementations of Interface1 actually need to work with params. I was attempting to not break the Interface Segregation Principle, by having lots of implementations with empty getParams() and setParams() methods but like you say, Interface2 is pretty useless on its own...

          – jml
          2 days ago








        • 2





          @jml then maybe a specification of Interface1 with your said methods would be better (interface Interface2 extends Interface1 { /* get and set params */ }

          – Lino
          2 days ago






        • 2





          @jml Then what Lino suggests is probably what you want. Request and ParametizedRequest are better than Request and HasParameters.

          – Michael
          2 days ago






        • 3





          @jml HasParameters doesn't feel like an interface, but an attribute. Maybe in reality what you need to do is add the methods to Request, like hasParameters(), getParameters() and setParameters(). With Java 8 you can even have those default to false, emptyList() and throw OperationNotSupportedException respectively if you don't want to have to implement them all the time. Java's Collection classes do this all the time.

          – jbx
          2 days ago








        • 1





          With Java 8 you could include your getParams() and setParams() in Interface1 with default do-nothing implementations, like public default void setParams(Params p) {} and public default Params getParams() { return null; }

          – Stephen P
          2 days ago
















        20















        I'm aware that I could have a wrapper interface that extends both
        interfaces, but then I could end up with multiple interfaces to cater
        for all the possible permutations of interfaces that can be
        implemented by the same class




        I suspect that if you're finding that lots of your classes implement different combinations of interfaces then either: your concrete classes are doing too much; or (less likely) your interfaces are too small and too specialised, to the point of being useless individually.



        If you have good reason for some code to require something that is both a Interface1 and a Interface2 then absolutely go ahead and make a combined version that extends both. If you struggle to think of an appropriate name for this (no, not FooAndBar) then that's an indicator that your design is wrong.



        Absolutely do not rely on casting anything. It should only be used as a last resort and usually only for very specific problems (e.g. serialization).



        My favourite and most-used design pattern is the decorator pattern as such most of my classes will only ever implement one interface (except for more generic interfaces such as Comparable). I would say that if your classes are frequently/always implementing more than one interface then that's a code smell.





        If you're instantiating the object and using it within the same scope then you should just be writing



        Example example = new Example();


        Just so it's clear (I'm not sure if this is what you were suggesting), under no circumstances should you ever be writing anything like this:



        Interface1 example = new Example();
        if (example instanceof Interface2) {
        ((Interface2) example).someInterface2Method();
        }





        share|improve this answer


























        • It is an interesting point you make when you say "to the point of being useless individually" - Interface2 in this example actually refers to an interface I have called HasParameters, which has methods getParams() and setParams() as not all implementations of Interface1 actually need to work with params. I was attempting to not break the Interface Segregation Principle, by having lots of implementations with empty getParams() and setParams() methods but like you say, Interface2 is pretty useless on its own...

          – jml
          2 days ago








        • 2





          @jml then maybe a specification of Interface1 with your said methods would be better (interface Interface2 extends Interface1 { /* get and set params */ }

          – Lino
          2 days ago






        • 2





          @jml Then what Lino suggests is probably what you want. Request and ParametizedRequest are better than Request and HasParameters.

          – Michael
          2 days ago






        • 3





          @jml HasParameters doesn't feel like an interface, but an attribute. Maybe in reality what you need to do is add the methods to Request, like hasParameters(), getParameters() and setParameters(). With Java 8 you can even have those default to false, emptyList() and throw OperationNotSupportedException respectively if you don't want to have to implement them all the time. Java's Collection classes do this all the time.

          – jbx
          2 days ago








        • 1





          With Java 8 you could include your getParams() and setParams() in Interface1 with default do-nothing implementations, like public default void setParams(Params p) {} and public default Params getParams() { return null; }

          – Stephen P
          2 days ago














        20












        20








        20








        I'm aware that I could have a wrapper interface that extends both
        interfaces, but then I could end up with multiple interfaces to cater
        for all the possible permutations of interfaces that can be
        implemented by the same class




        I suspect that if you're finding that lots of your classes implement different combinations of interfaces then either: your concrete classes are doing too much; or (less likely) your interfaces are too small and too specialised, to the point of being useless individually.



        If you have good reason for some code to require something that is both a Interface1 and a Interface2 then absolutely go ahead and make a combined version that extends both. If you struggle to think of an appropriate name for this (no, not FooAndBar) then that's an indicator that your design is wrong.



        Absolutely do not rely on casting anything. It should only be used as a last resort and usually only for very specific problems (e.g. serialization).



        My favourite and most-used design pattern is the decorator pattern as such most of my classes will only ever implement one interface (except for more generic interfaces such as Comparable). I would say that if your classes are frequently/always implementing more than one interface then that's a code smell.





        If you're instantiating the object and using it within the same scope then you should just be writing



        Example example = new Example();


        Just so it's clear (I'm not sure if this is what you were suggesting), under no circumstances should you ever be writing anything like this:



        Interface1 example = new Example();
        if (example instanceof Interface2) {
        ((Interface2) example).someInterface2Method();
        }





        share|improve this answer
















        I'm aware that I could have a wrapper interface that extends both
        interfaces, but then I could end up with multiple interfaces to cater
        for all the possible permutations of interfaces that can be
        implemented by the same class




        I suspect that if you're finding that lots of your classes implement different combinations of interfaces then either: your concrete classes are doing too much; or (less likely) your interfaces are too small and too specialised, to the point of being useless individually.



        If you have good reason for some code to require something that is both a Interface1 and a Interface2 then absolutely go ahead and make a combined version that extends both. If you struggle to think of an appropriate name for this (no, not FooAndBar) then that's an indicator that your design is wrong.



        Absolutely do not rely on casting anything. It should only be used as a last resort and usually only for very specific problems (e.g. serialization).



        My favourite and most-used design pattern is the decorator pattern as such most of my classes will only ever implement one interface (except for more generic interfaces such as Comparable). I would say that if your classes are frequently/always implementing more than one interface then that's a code smell.





        If you're instantiating the object and using it within the same scope then you should just be writing



        Example example = new Example();


        Just so it's clear (I'm not sure if this is what you were suggesting), under no circumstances should you ever be writing anything like this:



        Interface1 example = new Example();
        if (example instanceof Interface2) {
        ((Interface2) example).someInterface2Method();
        }






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 2 days ago

























        answered 2 days ago









        MichaelMichael

        19k73369




        19k73369













        • It is an interesting point you make when you say "to the point of being useless individually" - Interface2 in this example actually refers to an interface I have called HasParameters, which has methods getParams() and setParams() as not all implementations of Interface1 actually need to work with params. I was attempting to not break the Interface Segregation Principle, by having lots of implementations with empty getParams() and setParams() methods but like you say, Interface2 is pretty useless on its own...

          – jml
          2 days ago








        • 2





          @jml then maybe a specification of Interface1 with your said methods would be better (interface Interface2 extends Interface1 { /* get and set params */ }

          – Lino
          2 days ago






        • 2





          @jml Then what Lino suggests is probably what you want. Request and ParametizedRequest are better than Request and HasParameters.

          – Michael
          2 days ago






        • 3





          @jml HasParameters doesn't feel like an interface, but an attribute. Maybe in reality what you need to do is add the methods to Request, like hasParameters(), getParameters() and setParameters(). With Java 8 you can even have those default to false, emptyList() and throw OperationNotSupportedException respectively if you don't want to have to implement them all the time. Java's Collection classes do this all the time.

          – jbx
          2 days ago








        • 1





          With Java 8 you could include your getParams() and setParams() in Interface1 with default do-nothing implementations, like public default void setParams(Params p) {} and public default Params getParams() { return null; }

          – Stephen P
          2 days ago



















        • It is an interesting point you make when you say "to the point of being useless individually" - Interface2 in this example actually refers to an interface I have called HasParameters, which has methods getParams() and setParams() as not all implementations of Interface1 actually need to work with params. I was attempting to not break the Interface Segregation Principle, by having lots of implementations with empty getParams() and setParams() methods but like you say, Interface2 is pretty useless on its own...

          – jml
          2 days ago








        • 2





          @jml then maybe a specification of Interface1 with your said methods would be better (interface Interface2 extends Interface1 { /* get and set params */ }

          – Lino
          2 days ago






        • 2





          @jml Then what Lino suggests is probably what you want. Request and ParametizedRequest are better than Request and HasParameters.

          – Michael
          2 days ago






        • 3





          @jml HasParameters doesn't feel like an interface, but an attribute. Maybe in reality what you need to do is add the methods to Request, like hasParameters(), getParameters() and setParameters(). With Java 8 you can even have those default to false, emptyList() and throw OperationNotSupportedException respectively if you don't want to have to implement them all the time. Java's Collection classes do this all the time.

          – jbx
          2 days ago








        • 1





          With Java 8 you could include your getParams() and setParams() in Interface1 with default do-nothing implementations, like public default void setParams(Params p) {} and public default Params getParams() { return null; }

          – Stephen P
          2 days ago

















        It is an interesting point you make when you say "to the point of being useless individually" - Interface2 in this example actually refers to an interface I have called HasParameters, which has methods getParams() and setParams() as not all implementations of Interface1 actually need to work with params. I was attempting to not break the Interface Segregation Principle, by having lots of implementations with empty getParams() and setParams() methods but like you say, Interface2 is pretty useless on its own...

        – jml
        2 days ago







        It is an interesting point you make when you say "to the point of being useless individually" - Interface2 in this example actually refers to an interface I have called HasParameters, which has methods getParams() and setParams() as not all implementations of Interface1 actually need to work with params. I was attempting to not break the Interface Segregation Principle, by having lots of implementations with empty getParams() and setParams() methods but like you say, Interface2 is pretty useless on its own...

        – jml
        2 days ago






        2




        2





        @jml then maybe a specification of Interface1 with your said methods would be better (interface Interface2 extends Interface1 { /* get and set params */ }

        – Lino
        2 days ago





        @jml then maybe a specification of Interface1 with your said methods would be better (interface Interface2 extends Interface1 { /* get and set params */ }

        – Lino
        2 days ago




        2




        2





        @jml Then what Lino suggests is probably what you want. Request and ParametizedRequest are better than Request and HasParameters.

        – Michael
        2 days ago





        @jml Then what Lino suggests is probably what you want. Request and ParametizedRequest are better than Request and HasParameters.

        – Michael
        2 days ago




        3




        3





        @jml HasParameters doesn't feel like an interface, but an attribute. Maybe in reality what you need to do is add the methods to Request, like hasParameters(), getParameters() and setParameters(). With Java 8 you can even have those default to false, emptyList() and throw OperationNotSupportedException respectively if you don't want to have to implement them all the time. Java's Collection classes do this all the time.

        – jbx
        2 days ago







        @jml HasParameters doesn't feel like an interface, but an attribute. Maybe in reality what you need to do is add the methods to Request, like hasParameters(), getParameters() and setParameters(). With Java 8 you can even have those default to false, emptyList() and throw OperationNotSupportedException respectively if you don't want to have to implement them all the time. Java's Collection classes do this all the time.

        – jbx
        2 days ago






        1




        1





        With Java 8 you could include your getParams() and setParams() in Interface1 with default do-nothing implementations, like public default void setParams(Params p) {} and public default Params getParams() { return null; }

        – Stephen P
        2 days ago





        With Java 8 you could include your getParams() and setParams() in Interface1 with default do-nothing implementations, like public default void setParams(Params p) {} and public default Params getParams() { return null; }

        – Stephen P
        2 days ago













        19














        Your class can implement multiple interfaces fine, and it is not breaking any OOP principles. On the contrary, it is following the interface segregation principle.



        It is confusing why would you have a situation where something of type Interface1 is expected to provide someInterface2Method(). That is where your design is wrong.



        Think about it in a slightly different way: Imagine you have another method, void method1(Interface1 interface1). It can't expect interface1 to also be an instance of Interface2. If it was the case, the type of the argument should have been different. The example you have shown is precisely this, having a variable of type Interface1 but expecting it to also be of type Interface2.



        If you want to be able to call both methods, you should have the type of your variable example set to Example. That way you avoid the instanceof and type casting altogether.



        If your two interfaces Interface1 and Interface2 are not that loosely coupled, and you will often need to call methods from both, maybe separating the interfaces wasn't such a good idea, or maybe you want to have another interface which extends both.



        In general (although not always), instanceof checks and type casts often indicate some OO design flaw. Sometimes the design would fit for the rest of the program, but you would have a small case where it is simpler to type cast rather than refactor everything. But if possible you should always strive to avoid it at first, as part of your design.






        share|improve this answer






























          19














          Your class can implement multiple interfaces fine, and it is not breaking any OOP principles. On the contrary, it is following the interface segregation principle.



          It is confusing why would you have a situation where something of type Interface1 is expected to provide someInterface2Method(). That is where your design is wrong.



          Think about it in a slightly different way: Imagine you have another method, void method1(Interface1 interface1). It can't expect interface1 to also be an instance of Interface2. If it was the case, the type of the argument should have been different. The example you have shown is precisely this, having a variable of type Interface1 but expecting it to also be of type Interface2.



          If you want to be able to call both methods, you should have the type of your variable example set to Example. That way you avoid the instanceof and type casting altogether.



          If your two interfaces Interface1 and Interface2 are not that loosely coupled, and you will often need to call methods from both, maybe separating the interfaces wasn't such a good idea, or maybe you want to have another interface which extends both.



          In general (although not always), instanceof checks and type casts often indicate some OO design flaw. Sometimes the design would fit for the rest of the program, but you would have a small case where it is simpler to type cast rather than refactor everything. But if possible you should always strive to avoid it at first, as part of your design.






          share|improve this answer




























            19












            19








            19







            Your class can implement multiple interfaces fine, and it is not breaking any OOP principles. On the contrary, it is following the interface segregation principle.



            It is confusing why would you have a situation where something of type Interface1 is expected to provide someInterface2Method(). That is where your design is wrong.



            Think about it in a slightly different way: Imagine you have another method, void method1(Interface1 interface1). It can't expect interface1 to also be an instance of Interface2. If it was the case, the type of the argument should have been different. The example you have shown is precisely this, having a variable of type Interface1 but expecting it to also be of type Interface2.



            If you want to be able to call both methods, you should have the type of your variable example set to Example. That way you avoid the instanceof and type casting altogether.



            If your two interfaces Interface1 and Interface2 are not that loosely coupled, and you will often need to call methods from both, maybe separating the interfaces wasn't such a good idea, or maybe you want to have another interface which extends both.



            In general (although not always), instanceof checks and type casts often indicate some OO design flaw. Sometimes the design would fit for the rest of the program, but you would have a small case where it is simpler to type cast rather than refactor everything. But if possible you should always strive to avoid it at first, as part of your design.






            share|improve this answer















            Your class can implement multiple interfaces fine, and it is not breaking any OOP principles. On the contrary, it is following the interface segregation principle.



            It is confusing why would you have a situation where something of type Interface1 is expected to provide someInterface2Method(). That is where your design is wrong.



            Think about it in a slightly different way: Imagine you have another method, void method1(Interface1 interface1). It can't expect interface1 to also be an instance of Interface2. If it was the case, the type of the argument should have been different. The example you have shown is precisely this, having a variable of type Interface1 but expecting it to also be of type Interface2.



            If you want to be able to call both methods, you should have the type of your variable example set to Example. That way you avoid the instanceof and type casting altogether.



            If your two interfaces Interface1 and Interface2 are not that loosely coupled, and you will often need to call methods from both, maybe separating the interfaces wasn't such a good idea, or maybe you want to have another interface which extends both.



            In general (although not always), instanceof checks and type casts often indicate some OO design flaw. Sometimes the design would fit for the rest of the program, but you would have a small case where it is simpler to type cast rather than refactor everything. But if possible you should always strive to avoid it at first, as part of your design.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited yesterday

























            answered 2 days ago









            jbxjbx

            10.9k1057111




            10.9k1057111























                9














                You have two different options (I bet there are a lot more).



                The first is to create your own interface which extends the other two:



                interface Interface3 extends Interface1, Interface2 {}


                And then use that throughout your code:



                public void doSomething(Interface3 interface3){
                ...
                }


                The other way (and in my opinion the better one) is to use generics per method:



                public <T extends Interface1 & Interface2> void doSomething(T t){
                ...
                }


                The latter option is in fact less restricted than the former, because the generic type T gets dynamically inferred and thus leads to less coupling (a class doesn't have to implement a specific grouping interface, like the first example).






                share|improve this answer





















                • 1





                  "And then use that throughout your code" The significant downside to this is that you have to make Example (and any other classes) implement this class.

                  – Andy Turner
                  2 days ago











                • @Andy I agree and that's why the second approach is more flexible and may probably be preferred

                  – Lino
                  2 days ago






                • 5





                  It's worth stating your preferred option first; or, at the very least, stating "My preferred way" or similar, which is a much stronger endorsement than "the other way".

                  – Andy Turner
                  2 days ago






                • 4





                  While you are providing correct technical solutions to the issue, be wary of implementing workarounds when the underlying issue is an architecture one. You may find yourself with even more issues in the end stemming from an incorrect design.

                  – Vincent Savard
                  2 days ago


















                9














                You have two different options (I bet there are a lot more).



                The first is to create your own interface which extends the other two:



                interface Interface3 extends Interface1, Interface2 {}


                And then use that throughout your code:



                public void doSomething(Interface3 interface3){
                ...
                }


                The other way (and in my opinion the better one) is to use generics per method:



                public <T extends Interface1 & Interface2> void doSomething(T t){
                ...
                }


                The latter option is in fact less restricted than the former, because the generic type T gets dynamically inferred and thus leads to less coupling (a class doesn't have to implement a specific grouping interface, like the first example).






                share|improve this answer





















                • 1





                  "And then use that throughout your code" The significant downside to this is that you have to make Example (and any other classes) implement this class.

                  – Andy Turner
                  2 days ago











                • @Andy I agree and that's why the second approach is more flexible and may probably be preferred

                  – Lino
                  2 days ago






                • 5





                  It's worth stating your preferred option first; or, at the very least, stating "My preferred way" or similar, which is a much stronger endorsement than "the other way".

                  – Andy Turner
                  2 days ago






                • 4





                  While you are providing correct technical solutions to the issue, be wary of implementing workarounds when the underlying issue is an architecture one. You may find yourself with even more issues in the end stemming from an incorrect design.

                  – Vincent Savard
                  2 days ago
















                9












                9








                9







                You have two different options (I bet there are a lot more).



                The first is to create your own interface which extends the other two:



                interface Interface3 extends Interface1, Interface2 {}


                And then use that throughout your code:



                public void doSomething(Interface3 interface3){
                ...
                }


                The other way (and in my opinion the better one) is to use generics per method:



                public <T extends Interface1 & Interface2> void doSomething(T t){
                ...
                }


                The latter option is in fact less restricted than the former, because the generic type T gets dynamically inferred and thus leads to less coupling (a class doesn't have to implement a specific grouping interface, like the first example).






                share|improve this answer















                You have two different options (I bet there are a lot more).



                The first is to create your own interface which extends the other two:



                interface Interface3 extends Interface1, Interface2 {}


                And then use that throughout your code:



                public void doSomething(Interface3 interface3){
                ...
                }


                The other way (and in my opinion the better one) is to use generics per method:



                public <T extends Interface1 & Interface2> void doSomething(T t){
                ...
                }


                The latter option is in fact less restricted than the former, because the generic type T gets dynamically inferred and thus leads to less coupling (a class doesn't have to implement a specific grouping interface, like the first example).







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited yesterday









                Peter Mortensen

                13.5k1984111




                13.5k1984111










                answered 2 days ago









                LinoLino

                7,73421936




                7,73421936








                • 1





                  "And then use that throughout your code" The significant downside to this is that you have to make Example (and any other classes) implement this class.

                  – Andy Turner
                  2 days ago











                • @Andy I agree and that's why the second approach is more flexible and may probably be preferred

                  – Lino
                  2 days ago






                • 5





                  It's worth stating your preferred option first; or, at the very least, stating "My preferred way" or similar, which is a much stronger endorsement than "the other way".

                  – Andy Turner
                  2 days ago






                • 4





                  While you are providing correct technical solutions to the issue, be wary of implementing workarounds when the underlying issue is an architecture one. You may find yourself with even more issues in the end stemming from an incorrect design.

                  – Vincent Savard
                  2 days ago
















                • 1





                  "And then use that throughout your code" The significant downside to this is that you have to make Example (and any other classes) implement this class.

                  – Andy Turner
                  2 days ago











                • @Andy I agree and that's why the second approach is more flexible and may probably be preferred

                  – Lino
                  2 days ago






                • 5





                  It's worth stating your preferred option first; or, at the very least, stating "My preferred way" or similar, which is a much stronger endorsement than "the other way".

                  – Andy Turner
                  2 days ago






                • 4





                  While you are providing correct technical solutions to the issue, be wary of implementing workarounds when the underlying issue is an architecture one. You may find yourself with even more issues in the end stemming from an incorrect design.

                  – Vincent Savard
                  2 days ago










                1




                1





                "And then use that throughout your code" The significant downside to this is that you have to make Example (and any other classes) implement this class.

                – Andy Turner
                2 days ago





                "And then use that throughout your code" The significant downside to this is that you have to make Example (and any other classes) implement this class.

                – Andy Turner
                2 days ago













                @Andy I agree and that's why the second approach is more flexible and may probably be preferred

                – Lino
                2 days ago





                @Andy I agree and that's why the second approach is more flexible and may probably be preferred

                – Lino
                2 days ago




                5




                5





                It's worth stating your preferred option first; or, at the very least, stating "My preferred way" or similar, which is a much stronger endorsement than "the other way".

                – Andy Turner
                2 days ago





                It's worth stating your preferred option first; or, at the very least, stating "My preferred way" or similar, which is a much stronger endorsement than "the other way".

                – Andy Turner
                2 days ago




                4




                4





                While you are providing correct technical solutions to the issue, be wary of implementing workarounds when the underlying issue is an architecture one. You may find yourself with even more issues in the end stemming from an incorrect design.

                – Vincent Savard
                2 days ago







                While you are providing correct technical solutions to the issue, be wary of implementing workarounds when the underlying issue is an architecture one. You may find yourself with even more issues in the end stemming from an incorrect design.

                – Vincent Savard
                2 days ago













                5














                Your example does not break LSP, but it seems to break SRP. If you encounter such case where you need to cast an object to its 2nd interface, the method that contains such code can be considered busy.



                Implementing 2 (or more) interfaces in a class is fine. In deciding which interface to use as its data type depends entirely on the context of the code that will use it.



                Casting is fine, especially when changing context.



                class Payment implements Expirable, Limited {
                /* ... */
                }

                class PaymentProcessor {
                // Using payment here because i'm working with payments.
                public void process(Payment payment) {
                boolean expired = expirationChecker.check(payment);
                boolean pastLimit = limitChecker.check(payment);

                if (!expired && !pastLimit) {
                acceptPayment(payment);
                }
                }
                }

                class ExpirationChecker {
                // This the `Expirable` world, so i'm using Expirable here
                public boolean check(Expirable expirable) {
                // code
                }
                }

                class LimitChecker {
                // This class is about checking limits, thats why im using `Limited` here
                public boolean check(Limited limited) {
                // code
                }
                }





                share|improve this answer


























                • LSV? Don't you mean LSP?

                  – Peter Mortensen
                  yesterday











                • That was certainly a typo, sorry for that.

                  – KaNa0011
                  yesterday
















                5














                Your example does not break LSP, but it seems to break SRP. If you encounter such case where you need to cast an object to its 2nd interface, the method that contains such code can be considered busy.



                Implementing 2 (or more) interfaces in a class is fine. In deciding which interface to use as its data type depends entirely on the context of the code that will use it.



                Casting is fine, especially when changing context.



                class Payment implements Expirable, Limited {
                /* ... */
                }

                class PaymentProcessor {
                // Using payment here because i'm working with payments.
                public void process(Payment payment) {
                boolean expired = expirationChecker.check(payment);
                boolean pastLimit = limitChecker.check(payment);

                if (!expired && !pastLimit) {
                acceptPayment(payment);
                }
                }
                }

                class ExpirationChecker {
                // This the `Expirable` world, so i'm using Expirable here
                public boolean check(Expirable expirable) {
                // code
                }
                }

                class LimitChecker {
                // This class is about checking limits, thats why im using `Limited` here
                public boolean check(Limited limited) {
                // code
                }
                }





                share|improve this answer


























                • LSV? Don't you mean LSP?

                  – Peter Mortensen
                  yesterday











                • That was certainly a typo, sorry for that.

                  – KaNa0011
                  yesterday














                5












                5








                5







                Your example does not break LSP, but it seems to break SRP. If you encounter such case where you need to cast an object to its 2nd interface, the method that contains such code can be considered busy.



                Implementing 2 (or more) interfaces in a class is fine. In deciding which interface to use as its data type depends entirely on the context of the code that will use it.



                Casting is fine, especially when changing context.



                class Payment implements Expirable, Limited {
                /* ... */
                }

                class PaymentProcessor {
                // Using payment here because i'm working with payments.
                public void process(Payment payment) {
                boolean expired = expirationChecker.check(payment);
                boolean pastLimit = limitChecker.check(payment);

                if (!expired && !pastLimit) {
                acceptPayment(payment);
                }
                }
                }

                class ExpirationChecker {
                // This the `Expirable` world, so i'm using Expirable here
                public boolean check(Expirable expirable) {
                // code
                }
                }

                class LimitChecker {
                // This class is about checking limits, thats why im using `Limited` here
                public boolean check(Limited limited) {
                // code
                }
                }





                share|improve this answer















                Your example does not break LSP, but it seems to break SRP. If you encounter such case where you need to cast an object to its 2nd interface, the method that contains such code can be considered busy.



                Implementing 2 (or more) interfaces in a class is fine. In deciding which interface to use as its data type depends entirely on the context of the code that will use it.



                Casting is fine, especially when changing context.



                class Payment implements Expirable, Limited {
                /* ... */
                }

                class PaymentProcessor {
                // Using payment here because i'm working with payments.
                public void process(Payment payment) {
                boolean expired = expirationChecker.check(payment);
                boolean pastLimit = limitChecker.check(payment);

                if (!expired && !pastLimit) {
                acceptPayment(payment);
                }
                }
                }

                class ExpirationChecker {
                // This the `Expirable` world, so i'm using Expirable here
                public boolean check(Expirable expirable) {
                // code
                }
                }

                class LimitChecker {
                // This class is about checking limits, thats why im using `Limited` here
                public boolean check(Limited limited) {
                // code
                }
                }






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited yesterday

























                answered 2 days ago









                KaNa0011KaNa0011

                489311




                489311













                • LSV? Don't you mean LSP?

                  – Peter Mortensen
                  yesterday











                • That was certainly a typo, sorry for that.

                  – KaNa0011
                  yesterday



















                • LSV? Don't you mean LSP?

                  – Peter Mortensen
                  yesterday











                • That was certainly a typo, sorry for that.

                  – KaNa0011
                  yesterday

















                LSV? Don't you mean LSP?

                – Peter Mortensen
                yesterday





                LSV? Don't you mean LSP?

                – Peter Mortensen
                yesterday













                That was certainly a typo, sorry for that.

                – KaNa0011
                yesterday





                That was certainly a typo, sorry for that.

                – KaNa0011
                yesterday











                4














                The core issue



                Slightly tweaking your example so I can address the core issue:



                public void DoTheThing(Interface1 example)
                {
                if (example instanceof Interface2)
                {
                ((Interface2) example).someInterface2Method();
                }
                }


                So you defined the method DoTheThing(Interface1 example). This is basically saying "to do the thing, I need an Interface1 object".



                But then, in your method body, it appears that you actually need an Interface2 object. Then why didn't you ask for one in your method parameters? Quite obviously, you should've been asking for an Interface2



                What you're doing here is assuming that whatever Interface1 object you get will also be an Interface2 object. This is not something you can rely on. You might have some classes which implement both interfaces, but you might as well have some classes which only implement one and not the other.



                There is no inherent requirement whereby Interface1 and Interface2 need to both be implemented on the same object. You can't know (nor rely on the assumption) that this is the case.



                Unless you define the inherent requirement and apply it.



                interface InterfaceBoth extends Interface1, Interface2 {}

                public void DoTheThing(InterfaceBoth example)
                {
                example.someInterface2Method();
                }


                In this case, you've required InterfaceBoth object to both implement Interface1 and Interface2. So whenever you ask for an InterfaceBoth object, you can be sure to get an object which implements both Interface1 and Interface2, and thus you can use methods from either interface without even needing to cast or check the type.



                You (and the compiler) know that this method will always be available, and there's no chance of this not working.



                Note: You could've used Example instead of creating the InterfaceBoth interface, but then you would only be able to use objects of type Example and not any other class which would implement both interfaces. I assume you're interested in handling any class which implements both interfaces, not just Example.



                Deconstructing the issue further.



                Look at this code:



                ICarrot myObject = new Superman();


                If you assume this code compiles, what can you tell me about the Superman class? That it clearly implements the ICarrot interface. That is all you can tell me. You have no idea whether Superman implements the IShovel interface or not.



                So if I try to do this:



                myObject.SomeMethodThatIsFromSupermanButNotFromICarrot();


                or this:



                myObject.SomeMethodThatIsFromIShovelButNotFromICarrot();


                Should you be surprised if I told you this code compiles? You should, because this code doesn't compile.



                You may say "but I know that it's a Superman object which has this method!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman variable.



                You may say "but I know that it's a Superman object which implements the IShovel interface!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman or IShovel variable.



                Knowing this, let's look back at your code.



                Interface1 example = new Example();


                All you've said is that you have an Interface1 variable.



                if (example instanceof Interface2) {
                ((Interface2) example).someInterface2Method();
                }


                It makes no sense for you to assume that this Interface1 object also happens to implement a second unrelated interface. Even if this code works on a technical level, it is a sign of bad design, the developer is expecting some inherent correlation between two interfaces without actually having created this correlation.



                You may say "but I know I'm putting an Example object in, the compiler should know that too!" but you'd be missing the point that if this were a method parameter, you would have no way of knowing what the callers of your method are sending.



                public void DoTheThing(Interface1 example)
                {
                if (example instanceof Interface2)
                {
                ((Interface2) example).someInterface2Method();
                }
                }


                When other callers call this method, the compiler is only going to stop them if the passed object does not implement Interface1. The compiler is not going to stop someone from passing an object of a class which implements Interface1 but does not implement Interface2.






                share|improve this answer


























                • The first ~50% of your answer is explaining something that the OP already understands in a very long-winded way. "I'm aware that I could have a wrapper interface that extends both interfaces"

                  – Michael
                  yesterday













                • @Michael: That only applies to the small "Unless you define..." paragraph, not "The core issue". That second paragraph isn't just added to offer a solution, but also to explain how it ideologically differs from OP's initial situation, to further clarify why OP's implicit expectations are not acknowledged by the compiler. Understanding you can do it (which is what OP does know, you're right about that) is not the same as understanding why you should do it and why the compiler expects you to and refuses to otherwise accept the code.

                  – Flater
                  yesterday


















                4














                The core issue



                Slightly tweaking your example so I can address the core issue:



                public void DoTheThing(Interface1 example)
                {
                if (example instanceof Interface2)
                {
                ((Interface2) example).someInterface2Method();
                }
                }


                So you defined the method DoTheThing(Interface1 example). This is basically saying "to do the thing, I need an Interface1 object".



                But then, in your method body, it appears that you actually need an Interface2 object. Then why didn't you ask for one in your method parameters? Quite obviously, you should've been asking for an Interface2



                What you're doing here is assuming that whatever Interface1 object you get will also be an Interface2 object. This is not something you can rely on. You might have some classes which implement both interfaces, but you might as well have some classes which only implement one and not the other.



                There is no inherent requirement whereby Interface1 and Interface2 need to both be implemented on the same object. You can't know (nor rely on the assumption) that this is the case.



                Unless you define the inherent requirement and apply it.



                interface InterfaceBoth extends Interface1, Interface2 {}

                public void DoTheThing(InterfaceBoth example)
                {
                example.someInterface2Method();
                }


                In this case, you've required InterfaceBoth object to both implement Interface1 and Interface2. So whenever you ask for an InterfaceBoth object, you can be sure to get an object which implements both Interface1 and Interface2, and thus you can use methods from either interface without even needing to cast or check the type.



                You (and the compiler) know that this method will always be available, and there's no chance of this not working.



                Note: You could've used Example instead of creating the InterfaceBoth interface, but then you would only be able to use objects of type Example and not any other class which would implement both interfaces. I assume you're interested in handling any class which implements both interfaces, not just Example.



                Deconstructing the issue further.



                Look at this code:



                ICarrot myObject = new Superman();


                If you assume this code compiles, what can you tell me about the Superman class? That it clearly implements the ICarrot interface. That is all you can tell me. You have no idea whether Superman implements the IShovel interface or not.



                So if I try to do this:



                myObject.SomeMethodThatIsFromSupermanButNotFromICarrot();


                or this:



                myObject.SomeMethodThatIsFromIShovelButNotFromICarrot();


                Should you be surprised if I told you this code compiles? You should, because this code doesn't compile.



                You may say "but I know that it's a Superman object which has this method!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman variable.



                You may say "but I know that it's a Superman object which implements the IShovel interface!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman or IShovel variable.



                Knowing this, let's look back at your code.



                Interface1 example = new Example();


                All you've said is that you have an Interface1 variable.



                if (example instanceof Interface2) {
                ((Interface2) example).someInterface2Method();
                }


                It makes no sense for you to assume that this Interface1 object also happens to implement a second unrelated interface. Even if this code works on a technical level, it is a sign of bad design, the developer is expecting some inherent correlation between two interfaces without actually having created this correlation.



                You may say "but I know I'm putting an Example object in, the compiler should know that too!" but you'd be missing the point that if this were a method parameter, you would have no way of knowing what the callers of your method are sending.



                public void DoTheThing(Interface1 example)
                {
                if (example instanceof Interface2)
                {
                ((Interface2) example).someInterface2Method();
                }
                }


                When other callers call this method, the compiler is only going to stop them if the passed object does not implement Interface1. The compiler is not going to stop someone from passing an object of a class which implements Interface1 but does not implement Interface2.






                share|improve this answer


























                • The first ~50% of your answer is explaining something that the OP already understands in a very long-winded way. "I'm aware that I could have a wrapper interface that extends both interfaces"

                  – Michael
                  yesterday













                • @Michael: That only applies to the small "Unless you define..." paragraph, not "The core issue". That second paragraph isn't just added to offer a solution, but also to explain how it ideologically differs from OP's initial situation, to further clarify why OP's implicit expectations are not acknowledged by the compiler. Understanding you can do it (which is what OP does know, you're right about that) is not the same as understanding why you should do it and why the compiler expects you to and refuses to otherwise accept the code.

                  – Flater
                  yesterday
















                4












                4








                4







                The core issue



                Slightly tweaking your example so I can address the core issue:



                public void DoTheThing(Interface1 example)
                {
                if (example instanceof Interface2)
                {
                ((Interface2) example).someInterface2Method();
                }
                }


                So you defined the method DoTheThing(Interface1 example). This is basically saying "to do the thing, I need an Interface1 object".



                But then, in your method body, it appears that you actually need an Interface2 object. Then why didn't you ask for one in your method parameters? Quite obviously, you should've been asking for an Interface2



                What you're doing here is assuming that whatever Interface1 object you get will also be an Interface2 object. This is not something you can rely on. You might have some classes which implement both interfaces, but you might as well have some classes which only implement one and not the other.



                There is no inherent requirement whereby Interface1 and Interface2 need to both be implemented on the same object. You can't know (nor rely on the assumption) that this is the case.



                Unless you define the inherent requirement and apply it.



                interface InterfaceBoth extends Interface1, Interface2 {}

                public void DoTheThing(InterfaceBoth example)
                {
                example.someInterface2Method();
                }


                In this case, you've required InterfaceBoth object to both implement Interface1 and Interface2. So whenever you ask for an InterfaceBoth object, you can be sure to get an object which implements both Interface1 and Interface2, and thus you can use methods from either interface without even needing to cast or check the type.



                You (and the compiler) know that this method will always be available, and there's no chance of this not working.



                Note: You could've used Example instead of creating the InterfaceBoth interface, but then you would only be able to use objects of type Example and not any other class which would implement both interfaces. I assume you're interested in handling any class which implements both interfaces, not just Example.



                Deconstructing the issue further.



                Look at this code:



                ICarrot myObject = new Superman();


                If you assume this code compiles, what can you tell me about the Superman class? That it clearly implements the ICarrot interface. That is all you can tell me. You have no idea whether Superman implements the IShovel interface or not.



                So if I try to do this:



                myObject.SomeMethodThatIsFromSupermanButNotFromICarrot();


                or this:



                myObject.SomeMethodThatIsFromIShovelButNotFromICarrot();


                Should you be surprised if I told you this code compiles? You should, because this code doesn't compile.



                You may say "but I know that it's a Superman object which has this method!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman variable.



                You may say "but I know that it's a Superman object which implements the IShovel interface!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman or IShovel variable.



                Knowing this, let's look back at your code.



                Interface1 example = new Example();


                All you've said is that you have an Interface1 variable.



                if (example instanceof Interface2) {
                ((Interface2) example).someInterface2Method();
                }


                It makes no sense for you to assume that this Interface1 object also happens to implement a second unrelated interface. Even if this code works on a technical level, it is a sign of bad design, the developer is expecting some inherent correlation between two interfaces without actually having created this correlation.



                You may say "but I know I'm putting an Example object in, the compiler should know that too!" but you'd be missing the point that if this were a method parameter, you would have no way of knowing what the callers of your method are sending.



                public void DoTheThing(Interface1 example)
                {
                if (example instanceof Interface2)
                {
                ((Interface2) example).someInterface2Method();
                }
                }


                When other callers call this method, the compiler is only going to stop them if the passed object does not implement Interface1. The compiler is not going to stop someone from passing an object of a class which implements Interface1 but does not implement Interface2.






                share|improve this answer















                The core issue



                Slightly tweaking your example so I can address the core issue:



                public void DoTheThing(Interface1 example)
                {
                if (example instanceof Interface2)
                {
                ((Interface2) example).someInterface2Method();
                }
                }


                So you defined the method DoTheThing(Interface1 example). This is basically saying "to do the thing, I need an Interface1 object".



                But then, in your method body, it appears that you actually need an Interface2 object. Then why didn't you ask for one in your method parameters? Quite obviously, you should've been asking for an Interface2



                What you're doing here is assuming that whatever Interface1 object you get will also be an Interface2 object. This is not something you can rely on. You might have some classes which implement both interfaces, but you might as well have some classes which only implement one and not the other.



                There is no inherent requirement whereby Interface1 and Interface2 need to both be implemented on the same object. You can't know (nor rely on the assumption) that this is the case.



                Unless you define the inherent requirement and apply it.



                interface InterfaceBoth extends Interface1, Interface2 {}

                public void DoTheThing(InterfaceBoth example)
                {
                example.someInterface2Method();
                }


                In this case, you've required InterfaceBoth object to both implement Interface1 and Interface2. So whenever you ask for an InterfaceBoth object, you can be sure to get an object which implements both Interface1 and Interface2, and thus you can use methods from either interface without even needing to cast or check the type.



                You (and the compiler) know that this method will always be available, and there's no chance of this not working.



                Note: You could've used Example instead of creating the InterfaceBoth interface, but then you would only be able to use objects of type Example and not any other class which would implement both interfaces. I assume you're interested in handling any class which implements both interfaces, not just Example.



                Deconstructing the issue further.



                Look at this code:



                ICarrot myObject = new Superman();


                If you assume this code compiles, what can you tell me about the Superman class? That it clearly implements the ICarrot interface. That is all you can tell me. You have no idea whether Superman implements the IShovel interface or not.



                So if I try to do this:



                myObject.SomeMethodThatIsFromSupermanButNotFromICarrot();


                or this:



                myObject.SomeMethodThatIsFromIShovelButNotFromICarrot();


                Should you be surprised if I told you this code compiles? You should, because this code doesn't compile.



                You may say "but I know that it's a Superman object which has this method!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman variable.



                You may say "but I know that it's a Superman object which implements the IShovel interface!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman or IShovel variable.



                Knowing this, let's look back at your code.



                Interface1 example = new Example();


                All you've said is that you have an Interface1 variable.



                if (example instanceof Interface2) {
                ((Interface2) example).someInterface2Method();
                }


                It makes no sense for you to assume that this Interface1 object also happens to implement a second unrelated interface. Even if this code works on a technical level, it is a sign of bad design, the developer is expecting some inherent correlation between two interfaces without actually having created this correlation.



                You may say "but I know I'm putting an Example object in, the compiler should know that too!" but you'd be missing the point that if this were a method parameter, you would have no way of knowing what the callers of your method are sending.



                public void DoTheThing(Interface1 example)
                {
                if (example instanceof Interface2)
                {
                ((Interface2) example).someInterface2Method();
                }
                }


                When other callers call this method, the compiler is only going to stop them if the passed object does not implement Interface1. The compiler is not going to stop someone from passing an object of a class which implements Interface1 but does not implement Interface2.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited yesterday

























                answered yesterday









                FlaterFlater

                7,23732443




                7,23732443













                • The first ~50% of your answer is explaining something that the OP already understands in a very long-winded way. "I'm aware that I could have a wrapper interface that extends both interfaces"

                  – Michael
                  yesterday













                • @Michael: That only applies to the small "Unless you define..." paragraph, not "The core issue". That second paragraph isn't just added to offer a solution, but also to explain how it ideologically differs from OP's initial situation, to further clarify why OP's implicit expectations are not acknowledged by the compiler. Understanding you can do it (which is what OP does know, you're right about that) is not the same as understanding why you should do it and why the compiler expects you to and refuses to otherwise accept the code.

                  – Flater
                  yesterday





















                • The first ~50% of your answer is explaining something that the OP already understands in a very long-winded way. "I'm aware that I could have a wrapper interface that extends both interfaces"

                  – Michael
                  yesterday













                • @Michael: That only applies to the small "Unless you define..." paragraph, not "The core issue". That second paragraph isn't just added to offer a solution, but also to explain how it ideologically differs from OP's initial situation, to further clarify why OP's implicit expectations are not acknowledged by the compiler. Understanding you can do it (which is what OP does know, you're right about that) is not the same as understanding why you should do it and why the compiler expects you to and refuses to otherwise accept the code.

                  – Flater
                  yesterday



















                The first ~50% of your answer is explaining something that the OP already understands in a very long-winded way. "I'm aware that I could have a wrapper interface that extends both interfaces"

                – Michael
                yesterday







                The first ~50% of your answer is explaining something that the OP already understands in a very long-winded way. "I'm aware that I could have a wrapper interface that extends both interfaces"

                – Michael
                yesterday















                @Michael: That only applies to the small "Unless you define..." paragraph, not "The core issue". That second paragraph isn't just added to offer a solution, but also to explain how it ideologically differs from OP's initial situation, to further clarify why OP's implicit expectations are not acknowledged by the compiler. Understanding you can do it (which is what OP does know, you're right about that) is not the same as understanding why you should do it and why the compiler expects you to and refuses to otherwise accept the code.

                – Flater
                yesterday







                @Michael: That only applies to the small "Unless you define..." paragraph, not "The core issue". That second paragraph isn't just added to offer a solution, but also to explain how it ideologically differs from OP's initial situation, to further clarify why OP's implicit expectations are not acknowledged by the compiler. Understanding you can do it (which is what OP does know, you're right about that) is not the same as understanding why you should do it and why the compiler expects you to and refuses to otherwise accept the code.

                – Flater
                yesterday













                1














                Usually, many, client-specific interfaces are fine, and somewhat part of the Interface segregation principle (the "I" in SOLID). Some more specific points, on a technical level, have already been mentioned in other answers.



                Particularly that you can go too far with this segregation, by having a class like



                class Person implements FirstNameProvider, LastNameProvider, AgeProvider ... {
                @Override String getFirstName() {...}
                @Override String getLastName() {...}
                @Override int getAge() {...}
                ...
                }


                Or, conversely, that you have an implementing class that is too powerful, as in



                class Application implements DatabaseReader, DataProcessor, UserInteraction, Visualizer {
                ...
                }




                I think that the main point in the Interface Segregation Principle is that the interfaces should be client-specific. They should basically "summarize" the functions that are required by a certain client, for a certain task.



                To put it that way: The issue is to strike the right balance between the extremes that I sketched above. When I'm trying to figure out interfaces and their relationships (mutually, and in terms of the classes that implement them), I always try to take a step back and ask myself, in an intentionally naïve way: Who is going to receive what, and what is he going to do with it?



                Regarding your example: When all your clients always need the functionality of Interface1 and Interface2 at the same time, then you should consider either defining an



                interface Combined extends Interface1, Interface2 { }


                or not have different interfaces in the first place. On the other hand, when the functionalities are completely distinct and unrelated and never used together, then you should wonder why the single class is implementing them at the same time.



                At this point, one could refer to another principle, namely Composition over inheritance. Although it is not classically related to implementing multiple interfaces, composition can also be favorable in this case. For example, you could change your class to not implement the interfaces directly, but only provide instances that implement them:



                class Example {
                Interface1 getInterface1() { ... }
                Interface2 getInterface2() { ... }
                }


                It looks a bit odd in this Example (sic!), but depending on the complexity of the implementation of Interface1 and Interface2, it can really make sense to keep them separated.





                Edited in response to the comment:



                The intention here is not to pass the concrete class Example to methods that need both interfaces. A case where this could make sense is rather when a class combines the functionalities of both interfaces, but does not do so by directly implementing them at the same time. It's hard to make up an example that does not look too contrived, but something like this might bring the idea across:



                interface DatabaseReader { String read(); }
                interface DatabaseWriter { void write(String s); }

                class Database {
                DatabaseConnection connection = create();
                DatabaseReader reader = createReader(connection);
                DatabaseReader writer = createWriter(connection);

                DatabaseReader getReader() { return reader; }
                DatabaseReader getWriter() { return writer; }
                }


                The client will still rely on the interfaces. Methods like



                void create(DatabaseWriter writer) { ... }
                void read (DatabaseReader reader) { ... }
                void update(DatabaseReader reader, DatabaseWriter writer) { ... }


                could then be called with



                create(database.getWriter());
                read (database.getReader());
                update(database.getReader(), database.getWriter());


                respectively.






                share|improve this answer


























                • This is the correct answer. The interface is built for the contract that the client code needs fulfilled. If the client code reasonably expects to be able to call someInterface1Method AND someInterface2Method, then that is a new contract. From wikipedia on ISP: "no client should be forced to depend on methods it does not use." and "clients will only have to know about the methods that are of interest to them."

                  – Xtros
                  2 days ago













                • I'm not sure I agree with the last point. If you've decided that you can't conceptually make an interface such as Combined because the two interfaces are unrelated then dumping the two objects into one compositional object isn't any better. If they're conceptually unrelated, the consuming method(s) should just take two parameters.

                  – Michael
                  yesterday













                • @Michael I hesitated with the last point, because it might look odd or cause misunderstandings. To be clear: Did you understand this like the Example-object should be passed to a "consuming" method that needs both interfaces? This was not was I meant. (If it could be understood this way, I'd try to make this clearer...)

                  – Marco13
                  12 hours ago











                • Yeah, that kind of thing. What else would you use it for?

                  – Michael
                  11 hours ago











                • @Michael I added an 'edit'. If you think that this is toooo far fetched or contrived, I'd rather omit the (originally) last paragraph and the 'edit'...

                  – Marco13
                  4 hours ago
















                1














                Usually, many, client-specific interfaces are fine, and somewhat part of the Interface segregation principle (the "I" in SOLID). Some more specific points, on a technical level, have already been mentioned in other answers.



                Particularly that you can go too far with this segregation, by having a class like



                class Person implements FirstNameProvider, LastNameProvider, AgeProvider ... {
                @Override String getFirstName() {...}
                @Override String getLastName() {...}
                @Override int getAge() {...}
                ...
                }


                Or, conversely, that you have an implementing class that is too powerful, as in



                class Application implements DatabaseReader, DataProcessor, UserInteraction, Visualizer {
                ...
                }




                I think that the main point in the Interface Segregation Principle is that the interfaces should be client-specific. They should basically "summarize" the functions that are required by a certain client, for a certain task.



                To put it that way: The issue is to strike the right balance between the extremes that I sketched above. When I'm trying to figure out interfaces and their relationships (mutually, and in terms of the classes that implement them), I always try to take a step back and ask myself, in an intentionally naïve way: Who is going to receive what, and what is he going to do with it?



                Regarding your example: When all your clients always need the functionality of Interface1 and Interface2 at the same time, then you should consider either defining an



                interface Combined extends Interface1, Interface2 { }


                or not have different interfaces in the first place. On the other hand, when the functionalities are completely distinct and unrelated and never used together, then you should wonder why the single class is implementing them at the same time.



                At this point, one could refer to another principle, namely Composition over inheritance. Although it is not classically related to implementing multiple interfaces, composition can also be favorable in this case. For example, you could change your class to not implement the interfaces directly, but only provide instances that implement them:



                class Example {
                Interface1 getInterface1() { ... }
                Interface2 getInterface2() { ... }
                }


                It looks a bit odd in this Example (sic!), but depending on the complexity of the implementation of Interface1 and Interface2, it can really make sense to keep them separated.





                Edited in response to the comment:



                The intention here is not to pass the concrete class Example to methods that need both interfaces. A case where this could make sense is rather when a class combines the functionalities of both interfaces, but does not do so by directly implementing them at the same time. It's hard to make up an example that does not look too contrived, but something like this might bring the idea across:



                interface DatabaseReader { String read(); }
                interface DatabaseWriter { void write(String s); }

                class Database {
                DatabaseConnection connection = create();
                DatabaseReader reader = createReader(connection);
                DatabaseReader writer = createWriter(connection);

                DatabaseReader getReader() { return reader; }
                DatabaseReader getWriter() { return writer; }
                }


                The client will still rely on the interfaces. Methods like



                void create(DatabaseWriter writer) { ... }
                void read (DatabaseReader reader) { ... }
                void update(DatabaseReader reader, DatabaseWriter writer) { ... }


                could then be called with



                create(database.getWriter());
                read (database.getReader());
                update(database.getReader(), database.getWriter());


                respectively.






                share|improve this answer


























                • This is the correct answer. The interface is built for the contract that the client code needs fulfilled. If the client code reasonably expects to be able to call someInterface1Method AND someInterface2Method, then that is a new contract. From wikipedia on ISP: "no client should be forced to depend on methods it does not use." and "clients will only have to know about the methods that are of interest to them."

                  – Xtros
                  2 days ago













                • I'm not sure I agree with the last point. If you've decided that you can't conceptually make an interface such as Combined because the two interfaces are unrelated then dumping the two objects into one compositional object isn't any better. If they're conceptually unrelated, the consuming method(s) should just take two parameters.

                  – Michael
                  yesterday













                • @Michael I hesitated with the last point, because it might look odd or cause misunderstandings. To be clear: Did you understand this like the Example-object should be passed to a "consuming" method that needs both interfaces? This was not was I meant. (If it could be understood this way, I'd try to make this clearer...)

                  – Marco13
                  12 hours ago











                • Yeah, that kind of thing. What else would you use it for?

                  – Michael
                  11 hours ago











                • @Michael I added an 'edit'. If you think that this is toooo far fetched or contrived, I'd rather omit the (originally) last paragraph and the 'edit'...

                  – Marco13
                  4 hours ago














                1












                1








                1







                Usually, many, client-specific interfaces are fine, and somewhat part of the Interface segregation principle (the "I" in SOLID). Some more specific points, on a technical level, have already been mentioned in other answers.



                Particularly that you can go too far with this segregation, by having a class like



                class Person implements FirstNameProvider, LastNameProvider, AgeProvider ... {
                @Override String getFirstName() {...}
                @Override String getLastName() {...}
                @Override int getAge() {...}
                ...
                }


                Or, conversely, that you have an implementing class that is too powerful, as in



                class Application implements DatabaseReader, DataProcessor, UserInteraction, Visualizer {
                ...
                }




                I think that the main point in the Interface Segregation Principle is that the interfaces should be client-specific. They should basically "summarize" the functions that are required by a certain client, for a certain task.



                To put it that way: The issue is to strike the right balance between the extremes that I sketched above. When I'm trying to figure out interfaces and their relationships (mutually, and in terms of the classes that implement them), I always try to take a step back and ask myself, in an intentionally naïve way: Who is going to receive what, and what is he going to do with it?



                Regarding your example: When all your clients always need the functionality of Interface1 and Interface2 at the same time, then you should consider either defining an



                interface Combined extends Interface1, Interface2 { }


                or not have different interfaces in the first place. On the other hand, when the functionalities are completely distinct and unrelated and never used together, then you should wonder why the single class is implementing them at the same time.



                At this point, one could refer to another principle, namely Composition over inheritance. Although it is not classically related to implementing multiple interfaces, composition can also be favorable in this case. For example, you could change your class to not implement the interfaces directly, but only provide instances that implement them:



                class Example {
                Interface1 getInterface1() { ... }
                Interface2 getInterface2() { ... }
                }


                It looks a bit odd in this Example (sic!), but depending on the complexity of the implementation of Interface1 and Interface2, it can really make sense to keep them separated.





                Edited in response to the comment:



                The intention here is not to pass the concrete class Example to methods that need both interfaces. A case where this could make sense is rather when a class combines the functionalities of both interfaces, but does not do so by directly implementing them at the same time. It's hard to make up an example that does not look too contrived, but something like this might bring the idea across:



                interface DatabaseReader { String read(); }
                interface DatabaseWriter { void write(String s); }

                class Database {
                DatabaseConnection connection = create();
                DatabaseReader reader = createReader(connection);
                DatabaseReader writer = createWriter(connection);

                DatabaseReader getReader() { return reader; }
                DatabaseReader getWriter() { return writer; }
                }


                The client will still rely on the interfaces. Methods like



                void create(DatabaseWriter writer) { ... }
                void read (DatabaseReader reader) { ... }
                void update(DatabaseReader reader, DatabaseWriter writer) { ... }


                could then be called with



                create(database.getWriter());
                read (database.getReader());
                update(database.getReader(), database.getWriter());


                respectively.






                share|improve this answer















                Usually, many, client-specific interfaces are fine, and somewhat part of the Interface segregation principle (the "I" in SOLID). Some more specific points, on a technical level, have already been mentioned in other answers.



                Particularly that you can go too far with this segregation, by having a class like



                class Person implements FirstNameProvider, LastNameProvider, AgeProvider ... {
                @Override String getFirstName() {...}
                @Override String getLastName() {...}
                @Override int getAge() {...}
                ...
                }


                Or, conversely, that you have an implementing class that is too powerful, as in



                class Application implements DatabaseReader, DataProcessor, UserInteraction, Visualizer {
                ...
                }




                I think that the main point in the Interface Segregation Principle is that the interfaces should be client-specific. They should basically "summarize" the functions that are required by a certain client, for a certain task.



                To put it that way: The issue is to strike the right balance between the extremes that I sketched above. When I'm trying to figure out interfaces and their relationships (mutually, and in terms of the classes that implement them), I always try to take a step back and ask myself, in an intentionally naïve way: Who is going to receive what, and what is he going to do with it?



                Regarding your example: When all your clients always need the functionality of Interface1 and Interface2 at the same time, then you should consider either defining an



                interface Combined extends Interface1, Interface2 { }


                or not have different interfaces in the first place. On the other hand, when the functionalities are completely distinct and unrelated and never used together, then you should wonder why the single class is implementing them at the same time.



                At this point, one could refer to another principle, namely Composition over inheritance. Although it is not classically related to implementing multiple interfaces, composition can also be favorable in this case. For example, you could change your class to not implement the interfaces directly, but only provide instances that implement them:



                class Example {
                Interface1 getInterface1() { ... }
                Interface2 getInterface2() { ... }
                }


                It looks a bit odd in this Example (sic!), but depending on the complexity of the implementation of Interface1 and Interface2, it can really make sense to keep them separated.





                Edited in response to the comment:



                The intention here is not to pass the concrete class Example to methods that need both interfaces. A case where this could make sense is rather when a class combines the functionalities of both interfaces, but does not do so by directly implementing them at the same time. It's hard to make up an example that does not look too contrived, but something like this might bring the idea across:



                interface DatabaseReader { String read(); }
                interface DatabaseWriter { void write(String s); }

                class Database {
                DatabaseConnection connection = create();
                DatabaseReader reader = createReader(connection);
                DatabaseReader writer = createWriter(connection);

                DatabaseReader getReader() { return reader; }
                DatabaseReader getWriter() { return writer; }
                }


                The client will still rely on the interfaces. Methods like



                void create(DatabaseWriter writer) { ... }
                void read (DatabaseReader reader) { ... }
                void update(DatabaseReader reader, DatabaseWriter writer) { ... }


                could then be called with



                create(database.getWriter());
                read (database.getReader());
                update(database.getReader(), database.getWriter());


                respectively.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 4 hours ago

























                answered 2 days ago









                Marco13Marco13

                42.1k856108




                42.1k856108













                • This is the correct answer. The interface is built for the contract that the client code needs fulfilled. If the client code reasonably expects to be able to call someInterface1Method AND someInterface2Method, then that is a new contract. From wikipedia on ISP: "no client should be forced to depend on methods it does not use." and "clients will only have to know about the methods that are of interest to them."

                  – Xtros
                  2 days ago













                • I'm not sure I agree with the last point. If you've decided that you can't conceptually make an interface such as Combined because the two interfaces are unrelated then dumping the two objects into one compositional object isn't any better. If they're conceptually unrelated, the consuming method(s) should just take two parameters.

                  – Michael
                  yesterday













                • @Michael I hesitated with the last point, because it might look odd or cause misunderstandings. To be clear: Did you understand this like the Example-object should be passed to a "consuming" method that needs both interfaces? This was not was I meant. (If it could be understood this way, I'd try to make this clearer...)

                  – Marco13
                  12 hours ago











                • Yeah, that kind of thing. What else would you use it for?

                  – Michael
                  11 hours ago











                • @Michael I added an 'edit'. If you think that this is toooo far fetched or contrived, I'd rather omit the (originally) last paragraph and the 'edit'...

                  – Marco13
                  4 hours ago



















                • This is the correct answer. The interface is built for the contract that the client code needs fulfilled. If the client code reasonably expects to be able to call someInterface1Method AND someInterface2Method, then that is a new contract. From wikipedia on ISP: "no client should be forced to depend on methods it does not use." and "clients will only have to know about the methods that are of interest to them."

                  – Xtros
                  2 days ago













                • I'm not sure I agree with the last point. If you've decided that you can't conceptually make an interface such as Combined because the two interfaces are unrelated then dumping the two objects into one compositional object isn't any better. If they're conceptually unrelated, the consuming method(s) should just take two parameters.

                  – Michael
                  yesterday













                • @Michael I hesitated with the last point, because it might look odd or cause misunderstandings. To be clear: Did you understand this like the Example-object should be passed to a "consuming" method that needs both interfaces? This was not was I meant. (If it could be understood this way, I'd try to make this clearer...)

                  – Marco13
                  12 hours ago











                • Yeah, that kind of thing. What else would you use it for?

                  – Michael
                  11 hours ago











                • @Michael I added an 'edit'. If you think that this is toooo far fetched or contrived, I'd rather omit the (originally) last paragraph and the 'edit'...

                  – Marco13
                  4 hours ago

















                This is the correct answer. The interface is built for the contract that the client code needs fulfilled. If the client code reasonably expects to be able to call someInterface1Method AND someInterface2Method, then that is a new contract. From wikipedia on ISP: "no client should be forced to depend on methods it does not use." and "clients will only have to know about the methods that are of interest to them."

                – Xtros
                2 days ago







                This is the correct answer. The interface is built for the contract that the client code needs fulfilled. If the client code reasonably expects to be able to call someInterface1Method AND someInterface2Method, then that is a new contract. From wikipedia on ISP: "no client should be forced to depend on methods it does not use." and "clients will only have to know about the methods that are of interest to them."

                – Xtros
                2 days ago















                I'm not sure I agree with the last point. If you've decided that you can't conceptually make an interface such as Combined because the two interfaces are unrelated then dumping the two objects into one compositional object isn't any better. If they're conceptually unrelated, the consuming method(s) should just take two parameters.

                – Michael
                yesterday







                I'm not sure I agree with the last point. If you've decided that you can't conceptually make an interface such as Combined because the two interfaces are unrelated then dumping the two objects into one compositional object isn't any better. If they're conceptually unrelated, the consuming method(s) should just take two parameters.

                – Michael
                yesterday















                @Michael I hesitated with the last point, because it might look odd or cause misunderstandings. To be clear: Did you understand this like the Example-object should be passed to a "consuming" method that needs both interfaces? This was not was I meant. (If it could be understood this way, I'd try to make this clearer...)

                – Marco13
                12 hours ago





                @Michael I hesitated with the last point, because it might look odd or cause misunderstandings. To be clear: Did you understand this like the Example-object should be passed to a "consuming" method that needs both interfaces? This was not was I meant. (If it could be understood this way, I'd try to make this clearer...)

                – Marco13
                12 hours ago













                Yeah, that kind of thing. What else would you use it for?

                – Michael
                11 hours ago





                Yeah, that kind of thing. What else would you use it for?

                – Michael
                11 hours ago













                @Michael I added an 'edit'. If you think that this is toooo far fetched or contrived, I'd rather omit the (originally) last paragraph and the 'edit'...

                – Marco13
                4 hours ago





                @Michael I added an 'edit'. If you think that this is toooo far fetched or contrived, I'd rather omit the (originally) last paragraph and the 'edit'...

                – Marco13
                4 hours ago











                0














                The problem you describe often comes about through over-zealous application of the Interface Segregation Principle, encouraged by languages' inability to specify that members of one interface should, by default, be chained to static methods which could implement sensible behaviors.



                Consider, for example, a basic sequence/enumeration interface and the following behaviors:




                1. Produce an enumerator which can read out the objects if no other iterator has yet been created.


                2. Produce an enumerator which can read out the objects even if another iterator has already been created and used.


                3. Report how many items are in the sequence


                4. Report the value of the Nth item in the sequence


                5. Copy a range of items from the object into an array of that type.


                6. Yield a reference to an immutable object that can accommodate the above operations efficiently with contents that are guaranteed never to change.



                I would suggest that such abilities should be part of the basic sequence/enumeration interface, along with a method/property to indicate which of the above operations are meaningfully supported. Some kinds of single-shot on-demand enumerators (e.g. an infinite truly-random sequence generator) might not be able to support any of those functions, but segregating such functions into separate interfaces will make it much harder to produce efficient wrappers for many kinds of operations.



                One could produce a wrapper class that would accommodate all of the above operations, though not necessarily efficiently, on any finite sequence which supports the first ability. If, however, the class is being used to wrap an object that already supports some of those abilities (e.g. access the Nth item), having the wrapper use the underlying behaviors could be much more efficient than having it do everything via the second function above (e.g. creating a new enumerator, and using that to iteratively read and ignore items from the sequence until the desired one is reached).



                Having all objects that produce any kind of sequence support an interface that includes all of the above, along with an indication of what abilities are supported, would be cleaner than trying to have different interfaces for different subsets of abilities, and requiring that wrapper classes make explicit provision for any combinations they want to expose to their clients.






                share|improve this answer




























                  0














                  The problem you describe often comes about through over-zealous application of the Interface Segregation Principle, encouraged by languages' inability to specify that members of one interface should, by default, be chained to static methods which could implement sensible behaviors.



                  Consider, for example, a basic sequence/enumeration interface and the following behaviors:




                  1. Produce an enumerator which can read out the objects if no other iterator has yet been created.


                  2. Produce an enumerator which can read out the objects even if another iterator has already been created and used.


                  3. Report how many items are in the sequence


                  4. Report the value of the Nth item in the sequence


                  5. Copy a range of items from the object into an array of that type.


                  6. Yield a reference to an immutable object that can accommodate the above operations efficiently with contents that are guaranteed never to change.



                  I would suggest that such abilities should be part of the basic sequence/enumeration interface, along with a method/property to indicate which of the above operations are meaningfully supported. Some kinds of single-shot on-demand enumerators (e.g. an infinite truly-random sequence generator) might not be able to support any of those functions, but segregating such functions into separate interfaces will make it much harder to produce efficient wrappers for many kinds of operations.



                  One could produce a wrapper class that would accommodate all of the above operations, though not necessarily efficiently, on any finite sequence which supports the first ability. If, however, the class is being used to wrap an object that already supports some of those abilities (e.g. access the Nth item), having the wrapper use the underlying behaviors could be much more efficient than having it do everything via the second function above (e.g. creating a new enumerator, and using that to iteratively read and ignore items from the sequence until the desired one is reached).



                  Having all objects that produce any kind of sequence support an interface that includes all of the above, along with an indication of what abilities are supported, would be cleaner than trying to have different interfaces for different subsets of abilities, and requiring that wrapper classes make explicit provision for any combinations they want to expose to their clients.






                  share|improve this answer


























                    0












                    0








                    0







                    The problem you describe often comes about through over-zealous application of the Interface Segregation Principle, encouraged by languages' inability to specify that members of one interface should, by default, be chained to static methods which could implement sensible behaviors.



                    Consider, for example, a basic sequence/enumeration interface and the following behaviors:




                    1. Produce an enumerator which can read out the objects if no other iterator has yet been created.


                    2. Produce an enumerator which can read out the objects even if another iterator has already been created and used.


                    3. Report how many items are in the sequence


                    4. Report the value of the Nth item in the sequence


                    5. Copy a range of items from the object into an array of that type.


                    6. Yield a reference to an immutable object that can accommodate the above operations efficiently with contents that are guaranteed never to change.



                    I would suggest that such abilities should be part of the basic sequence/enumeration interface, along with a method/property to indicate which of the above operations are meaningfully supported. Some kinds of single-shot on-demand enumerators (e.g. an infinite truly-random sequence generator) might not be able to support any of those functions, but segregating such functions into separate interfaces will make it much harder to produce efficient wrappers for many kinds of operations.



                    One could produce a wrapper class that would accommodate all of the above operations, though not necessarily efficiently, on any finite sequence which supports the first ability. If, however, the class is being used to wrap an object that already supports some of those abilities (e.g. access the Nth item), having the wrapper use the underlying behaviors could be much more efficient than having it do everything via the second function above (e.g. creating a new enumerator, and using that to iteratively read and ignore items from the sequence until the desired one is reached).



                    Having all objects that produce any kind of sequence support an interface that includes all of the above, along with an indication of what abilities are supported, would be cleaner than trying to have different interfaces for different subsets of abilities, and requiring that wrapper classes make explicit provision for any combinations they want to expose to their clients.






                    share|improve this answer













                    The problem you describe often comes about through over-zealous application of the Interface Segregation Principle, encouraged by languages' inability to specify that members of one interface should, by default, be chained to static methods which could implement sensible behaviors.



                    Consider, for example, a basic sequence/enumeration interface and the following behaviors:




                    1. Produce an enumerator which can read out the objects if no other iterator has yet been created.


                    2. Produce an enumerator which can read out the objects even if another iterator has already been created and used.


                    3. Report how many items are in the sequence


                    4. Report the value of the Nth item in the sequence


                    5. Copy a range of items from the object into an array of that type.


                    6. Yield a reference to an immutable object that can accommodate the above operations efficiently with contents that are guaranteed never to change.



                    I would suggest that such abilities should be part of the basic sequence/enumeration interface, along with a method/property to indicate which of the above operations are meaningfully supported. Some kinds of single-shot on-demand enumerators (e.g. an infinite truly-random sequence generator) might not be able to support any of those functions, but segregating such functions into separate interfaces will make it much harder to produce efficient wrappers for many kinds of operations.



                    One could produce a wrapper class that would accommodate all of the above operations, though not necessarily efficiently, on any finite sequence which supports the first ability. If, however, the class is being used to wrap an object that already supports some of those abilities (e.g. access the Nth item), having the wrapper use the underlying behaviors could be much more efficient than having it do everything via the second function above (e.g. creating a new enumerator, and using that to iteratively read and ignore items from the sequence until the desired one is reached).



                    Having all objects that produce any kind of sequence support an interface that includes all of the above, along with an indication of what abilities are supported, would be cleaner than trying to have different interfaces for different subsets of abilities, and requiring that wrapper classes make explicit provision for any combinations they want to expose to their clients.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered 2 days ago









                    supercatsupercat

                    56.5k2117150




                    56.5k2117150























                        0














                        With the help of various posts and comments on this page, a solution has been produced, which I feel is correct for my scenario.



                        The following shows the iterative changes to the solution to meet SOLID principles.



                        Requirement



                        To produce the response for a web service, key + object pairs are added to a response object. There are lots of different key + object pairs that need to be added, each of which may have unique processing required to transform the data from the source to the format required in the response.



                        From this it is clear that whilst the different key / value pairs may have different processing requirements to transform the source data to the target response object, they all have a common goal of adding an object to the response object.



                        Therefore, the following interface was produced in solution iteration 1:



                        Solution Iteration 1



                        ResponseObjectProvider<T, S> {
                        void addObject(T targetObject, S sourceObject, String targetKey);
                        }


                        Any developer that needs to add an object to the response can now do so using an existing implementation that matches their requirement, or add a new implementation given a new scenario



                        This is great as we have a common interface which acts as a contract for this common practise of adding response objects



                        However, one scenario requires that the target object should be taken from the source object given a particular key, "identifier".



                        There are options here, the first is to add an implementation of the existing interface as follows:



                        public class GetIdentifierResponseObjectProvider<T extends Map, S extends Map> implements ResponseObjectProvider<T, S> {
                        public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                        targetObject.put(targetKey, sourceObject.get("identifier"));
                        }
                        }


                        This works, however this scenario could be required for other source object keys ("startDate", "endDate" etc...) so this implementation should be made more generic to allow for reuse in this scenario.



                        Additionally, other implementations may require more context information to perform the addObject operation... So a new generic type should be added to cater for this



                        Solution Iteration 2



                        ResponseObjectProvider<T, S, U> {
                        void addObject(T targetObject, S sourceObject, String targetKey);
                        void setParams(U params);
                        U getParams();
                        }


                        This interface caters for both usage scenarios; the implementations that require additional params to perform the addObject operation and the implementations that do not



                        However, considering the latter of the usage scenarios, the implementations that do not require additional parameters will break the SOLID Interface Segregation Principle as these implementations will override getParams and setParams methods but not implement them. e.g:



                        public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S, U> {
                        public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                        targetObject.put(targetKey, sourceObject.get(U));
                        }

                        public void setParams(U params) {
                        //unimplemented method
                        }

                        U getParams() {
                        //unimplemented method
                        }

                        }


                        Solution Iteration 3



                        To fix the Interface Segregation issue, the getParams and setParams interface methods were moved into a new Interface:



                        public interface ParametersProvider<T> {
                        void setParams(T params);
                        T getParams();
                        }


                        The implementations that require parameters can now implement the ParametersProvider interface:



                        public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S>, ParametersProvider<U>

                        private String params;
                        public void setParams(U params) {
                        this.params = params;
                        }

                        public U getParams() {
                        return this.params;
                        }

                        public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                        targetObject.put(targetKey, sourceObject.get(params));
                        }
                        }


                        This solves the Interface Segregation issue but causes two more issues... If the calling client wants to program to an interface, i.e:



                        ResponseObjectProvider responseObjectProvider = new  GetObjectBySourceKeyResponseObjectProvider<>();


                        Then the addObject method will be available to the instance, but NOT the getParams and setParams methods of the ParametersProvider interface... To call these a cast is required, and to be safe an instanceof check should also be performed:



                        if(responseObjectProvider instanceof ParametersProvider) {
                        ((ParametersProvider)responseObjectProvider).setParams("identifier");
                        }


                        Not only is this undesirable it also breaks the Liskov Substitution Principle - "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program"



                        i.e. if we replaced an implementation of ResponseObjectProvider that also implements ParametersProvider, with an implementation that does not implement ParametersProvider then this could alter the some of the desirable properties of the program... Additionally, the client needs to be aware of which implementation is in use to call the correct methods



                        An additional problem is the usage for calling clients. If the calling client wanted to use an instance that implements both interfaces to perform addObject multiple times, the setParams method would need to be called before addObject... This could cause avoidable bugs if care is not taken when calling.



                        Solution Iteration 4 - Final Solution



                        The interfaces produced from Solution Iteration 3 solve all of the currently known usage requirements, with some flexibility provided by generics for implementation using different types. However, this solution breaks the Liskov Substitution Principle and has a non-obvious usage of setParams for the calling client



                        The solution is to have two separate interfaces, ParameterisedResponseObjectProvider and ResponseObjectProvider.



                        This allows the client to program to an interface, and would select the appropriate interface depending on whether the objects being added to the response require additional parameters or not



                        The new interface was first implemented as an extension of ResponseObjectProvider:



                        public interface ParameterisedResponseObjectProvider<T,S,U> extends ResponseObjectProvider<T, S> {
                        void setParams(U params);
                        U getParams();
                        }


                        However, this still had the usage issue, where the calling client would first need to call setParams before calling addObject and also make the code less readable.



                        So the final solution has two separate interfaces defined as follows:



                        public interface ResponseObjectProvider<T, S> {
                        void addObject(T targetObject, S sourceObject, String targetKey);
                        }


                        public interface ParameterisedResponseObjectProvider<T,S,U> {
                        void addObject(T targetObject, S sourceObject, String targetKey, U params);
                        }


                        This solution solves the breaches of Interface Segregation and Liskov Substitution principles and also improves the usage for calling clients and improves the readability of the code.



                        It does mean that the client needs to be aware of the different interfaces, but since the contracts are different this seems to be a justified decision especially when considering all the issues that the solution has avoided.






                        share|improve this answer




























                          0














                          With the help of various posts and comments on this page, a solution has been produced, which I feel is correct for my scenario.



                          The following shows the iterative changes to the solution to meet SOLID principles.



                          Requirement



                          To produce the response for a web service, key + object pairs are added to a response object. There are lots of different key + object pairs that need to be added, each of which may have unique processing required to transform the data from the source to the format required in the response.



                          From this it is clear that whilst the different key / value pairs may have different processing requirements to transform the source data to the target response object, they all have a common goal of adding an object to the response object.



                          Therefore, the following interface was produced in solution iteration 1:



                          Solution Iteration 1



                          ResponseObjectProvider<T, S> {
                          void addObject(T targetObject, S sourceObject, String targetKey);
                          }


                          Any developer that needs to add an object to the response can now do so using an existing implementation that matches their requirement, or add a new implementation given a new scenario



                          This is great as we have a common interface which acts as a contract for this common practise of adding response objects



                          However, one scenario requires that the target object should be taken from the source object given a particular key, "identifier".



                          There are options here, the first is to add an implementation of the existing interface as follows:



                          public class GetIdentifierResponseObjectProvider<T extends Map, S extends Map> implements ResponseObjectProvider<T, S> {
                          public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                          targetObject.put(targetKey, sourceObject.get("identifier"));
                          }
                          }


                          This works, however this scenario could be required for other source object keys ("startDate", "endDate" etc...) so this implementation should be made more generic to allow for reuse in this scenario.



                          Additionally, other implementations may require more context information to perform the addObject operation... So a new generic type should be added to cater for this



                          Solution Iteration 2



                          ResponseObjectProvider<T, S, U> {
                          void addObject(T targetObject, S sourceObject, String targetKey);
                          void setParams(U params);
                          U getParams();
                          }


                          This interface caters for both usage scenarios; the implementations that require additional params to perform the addObject operation and the implementations that do not



                          However, considering the latter of the usage scenarios, the implementations that do not require additional parameters will break the SOLID Interface Segregation Principle as these implementations will override getParams and setParams methods but not implement them. e.g:



                          public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S, U> {
                          public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                          targetObject.put(targetKey, sourceObject.get(U));
                          }

                          public void setParams(U params) {
                          //unimplemented method
                          }

                          U getParams() {
                          //unimplemented method
                          }

                          }


                          Solution Iteration 3



                          To fix the Interface Segregation issue, the getParams and setParams interface methods were moved into a new Interface:



                          public interface ParametersProvider<T> {
                          void setParams(T params);
                          T getParams();
                          }


                          The implementations that require parameters can now implement the ParametersProvider interface:



                          public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S>, ParametersProvider<U>

                          private String params;
                          public void setParams(U params) {
                          this.params = params;
                          }

                          public U getParams() {
                          return this.params;
                          }

                          public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                          targetObject.put(targetKey, sourceObject.get(params));
                          }
                          }


                          This solves the Interface Segregation issue but causes two more issues... If the calling client wants to program to an interface, i.e:



                          ResponseObjectProvider responseObjectProvider = new  GetObjectBySourceKeyResponseObjectProvider<>();


                          Then the addObject method will be available to the instance, but NOT the getParams and setParams methods of the ParametersProvider interface... To call these a cast is required, and to be safe an instanceof check should also be performed:



                          if(responseObjectProvider instanceof ParametersProvider) {
                          ((ParametersProvider)responseObjectProvider).setParams("identifier");
                          }


                          Not only is this undesirable it also breaks the Liskov Substitution Principle - "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program"



                          i.e. if we replaced an implementation of ResponseObjectProvider that also implements ParametersProvider, with an implementation that does not implement ParametersProvider then this could alter the some of the desirable properties of the program... Additionally, the client needs to be aware of which implementation is in use to call the correct methods



                          An additional problem is the usage for calling clients. If the calling client wanted to use an instance that implements both interfaces to perform addObject multiple times, the setParams method would need to be called before addObject... This could cause avoidable bugs if care is not taken when calling.



                          Solution Iteration 4 - Final Solution



                          The interfaces produced from Solution Iteration 3 solve all of the currently known usage requirements, with some flexibility provided by generics for implementation using different types. However, this solution breaks the Liskov Substitution Principle and has a non-obvious usage of setParams for the calling client



                          The solution is to have two separate interfaces, ParameterisedResponseObjectProvider and ResponseObjectProvider.



                          This allows the client to program to an interface, and would select the appropriate interface depending on whether the objects being added to the response require additional parameters or not



                          The new interface was first implemented as an extension of ResponseObjectProvider:



                          public interface ParameterisedResponseObjectProvider<T,S,U> extends ResponseObjectProvider<T, S> {
                          void setParams(U params);
                          U getParams();
                          }


                          However, this still had the usage issue, where the calling client would first need to call setParams before calling addObject and also make the code less readable.



                          So the final solution has two separate interfaces defined as follows:



                          public interface ResponseObjectProvider<T, S> {
                          void addObject(T targetObject, S sourceObject, String targetKey);
                          }


                          public interface ParameterisedResponseObjectProvider<T,S,U> {
                          void addObject(T targetObject, S sourceObject, String targetKey, U params);
                          }


                          This solution solves the breaches of Interface Segregation and Liskov Substitution principles and also improves the usage for calling clients and improves the readability of the code.



                          It does mean that the client needs to be aware of the different interfaces, but since the contracts are different this seems to be a justified decision especially when considering all the issues that the solution has avoided.






                          share|improve this answer


























                            0












                            0








                            0







                            With the help of various posts and comments on this page, a solution has been produced, which I feel is correct for my scenario.



                            The following shows the iterative changes to the solution to meet SOLID principles.



                            Requirement



                            To produce the response for a web service, key + object pairs are added to a response object. There are lots of different key + object pairs that need to be added, each of which may have unique processing required to transform the data from the source to the format required in the response.



                            From this it is clear that whilst the different key / value pairs may have different processing requirements to transform the source data to the target response object, they all have a common goal of adding an object to the response object.



                            Therefore, the following interface was produced in solution iteration 1:



                            Solution Iteration 1



                            ResponseObjectProvider<T, S> {
                            void addObject(T targetObject, S sourceObject, String targetKey);
                            }


                            Any developer that needs to add an object to the response can now do so using an existing implementation that matches their requirement, or add a new implementation given a new scenario



                            This is great as we have a common interface which acts as a contract for this common practise of adding response objects



                            However, one scenario requires that the target object should be taken from the source object given a particular key, "identifier".



                            There are options here, the first is to add an implementation of the existing interface as follows:



                            public class GetIdentifierResponseObjectProvider<T extends Map, S extends Map> implements ResponseObjectProvider<T, S> {
                            public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                            targetObject.put(targetKey, sourceObject.get("identifier"));
                            }
                            }


                            This works, however this scenario could be required for other source object keys ("startDate", "endDate" etc...) so this implementation should be made more generic to allow for reuse in this scenario.



                            Additionally, other implementations may require more context information to perform the addObject operation... So a new generic type should be added to cater for this



                            Solution Iteration 2



                            ResponseObjectProvider<T, S, U> {
                            void addObject(T targetObject, S sourceObject, String targetKey);
                            void setParams(U params);
                            U getParams();
                            }


                            This interface caters for both usage scenarios; the implementations that require additional params to perform the addObject operation and the implementations that do not



                            However, considering the latter of the usage scenarios, the implementations that do not require additional parameters will break the SOLID Interface Segregation Principle as these implementations will override getParams and setParams methods but not implement them. e.g:



                            public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S, U> {
                            public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                            targetObject.put(targetKey, sourceObject.get(U));
                            }

                            public void setParams(U params) {
                            //unimplemented method
                            }

                            U getParams() {
                            //unimplemented method
                            }

                            }


                            Solution Iteration 3



                            To fix the Interface Segregation issue, the getParams and setParams interface methods were moved into a new Interface:



                            public interface ParametersProvider<T> {
                            void setParams(T params);
                            T getParams();
                            }


                            The implementations that require parameters can now implement the ParametersProvider interface:



                            public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S>, ParametersProvider<U>

                            private String params;
                            public void setParams(U params) {
                            this.params = params;
                            }

                            public U getParams() {
                            return this.params;
                            }

                            public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                            targetObject.put(targetKey, sourceObject.get(params));
                            }
                            }


                            This solves the Interface Segregation issue but causes two more issues... If the calling client wants to program to an interface, i.e:



                            ResponseObjectProvider responseObjectProvider = new  GetObjectBySourceKeyResponseObjectProvider<>();


                            Then the addObject method will be available to the instance, but NOT the getParams and setParams methods of the ParametersProvider interface... To call these a cast is required, and to be safe an instanceof check should also be performed:



                            if(responseObjectProvider instanceof ParametersProvider) {
                            ((ParametersProvider)responseObjectProvider).setParams("identifier");
                            }


                            Not only is this undesirable it also breaks the Liskov Substitution Principle - "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program"



                            i.e. if we replaced an implementation of ResponseObjectProvider that also implements ParametersProvider, with an implementation that does not implement ParametersProvider then this could alter the some of the desirable properties of the program... Additionally, the client needs to be aware of which implementation is in use to call the correct methods



                            An additional problem is the usage for calling clients. If the calling client wanted to use an instance that implements both interfaces to perform addObject multiple times, the setParams method would need to be called before addObject... This could cause avoidable bugs if care is not taken when calling.



                            Solution Iteration 4 - Final Solution



                            The interfaces produced from Solution Iteration 3 solve all of the currently known usage requirements, with some flexibility provided by generics for implementation using different types. However, this solution breaks the Liskov Substitution Principle and has a non-obvious usage of setParams for the calling client



                            The solution is to have two separate interfaces, ParameterisedResponseObjectProvider and ResponseObjectProvider.



                            This allows the client to program to an interface, and would select the appropriate interface depending on whether the objects being added to the response require additional parameters or not



                            The new interface was first implemented as an extension of ResponseObjectProvider:



                            public interface ParameterisedResponseObjectProvider<T,S,U> extends ResponseObjectProvider<T, S> {
                            void setParams(U params);
                            U getParams();
                            }


                            However, this still had the usage issue, where the calling client would first need to call setParams before calling addObject and also make the code less readable.



                            So the final solution has two separate interfaces defined as follows:



                            public interface ResponseObjectProvider<T, S> {
                            void addObject(T targetObject, S sourceObject, String targetKey);
                            }


                            public interface ParameterisedResponseObjectProvider<T,S,U> {
                            void addObject(T targetObject, S sourceObject, String targetKey, U params);
                            }


                            This solution solves the breaches of Interface Segregation and Liskov Substitution principles and also improves the usage for calling clients and improves the readability of the code.



                            It does mean that the client needs to be aware of the different interfaces, but since the contracts are different this seems to be a justified decision especially when considering all the issues that the solution has avoided.






                            share|improve this answer













                            With the help of various posts and comments on this page, a solution has been produced, which I feel is correct for my scenario.



                            The following shows the iterative changes to the solution to meet SOLID principles.



                            Requirement



                            To produce the response for a web service, key + object pairs are added to a response object. There are lots of different key + object pairs that need to be added, each of which may have unique processing required to transform the data from the source to the format required in the response.



                            From this it is clear that whilst the different key / value pairs may have different processing requirements to transform the source data to the target response object, they all have a common goal of adding an object to the response object.



                            Therefore, the following interface was produced in solution iteration 1:



                            Solution Iteration 1



                            ResponseObjectProvider<T, S> {
                            void addObject(T targetObject, S sourceObject, String targetKey);
                            }


                            Any developer that needs to add an object to the response can now do so using an existing implementation that matches their requirement, or add a new implementation given a new scenario



                            This is great as we have a common interface which acts as a contract for this common practise of adding response objects



                            However, one scenario requires that the target object should be taken from the source object given a particular key, "identifier".



                            There are options here, the first is to add an implementation of the existing interface as follows:



                            public class GetIdentifierResponseObjectProvider<T extends Map, S extends Map> implements ResponseObjectProvider<T, S> {
                            public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                            targetObject.put(targetKey, sourceObject.get("identifier"));
                            }
                            }


                            This works, however this scenario could be required for other source object keys ("startDate", "endDate" etc...) so this implementation should be made more generic to allow for reuse in this scenario.



                            Additionally, other implementations may require more context information to perform the addObject operation... So a new generic type should be added to cater for this



                            Solution Iteration 2



                            ResponseObjectProvider<T, S, U> {
                            void addObject(T targetObject, S sourceObject, String targetKey);
                            void setParams(U params);
                            U getParams();
                            }


                            This interface caters for both usage scenarios; the implementations that require additional params to perform the addObject operation and the implementations that do not



                            However, considering the latter of the usage scenarios, the implementations that do not require additional parameters will break the SOLID Interface Segregation Principle as these implementations will override getParams and setParams methods but not implement them. e.g:



                            public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S, U> {
                            public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                            targetObject.put(targetKey, sourceObject.get(U));
                            }

                            public void setParams(U params) {
                            //unimplemented method
                            }

                            U getParams() {
                            //unimplemented method
                            }

                            }


                            Solution Iteration 3



                            To fix the Interface Segregation issue, the getParams and setParams interface methods were moved into a new Interface:



                            public interface ParametersProvider<T> {
                            void setParams(T params);
                            T getParams();
                            }


                            The implementations that require parameters can now implement the ParametersProvider interface:



                            public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S>, ParametersProvider<U>

                            private String params;
                            public void setParams(U params) {
                            this.params = params;
                            }

                            public U getParams() {
                            return this.params;
                            }

                            public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
                            targetObject.put(targetKey, sourceObject.get(params));
                            }
                            }


                            This solves the Interface Segregation issue but causes two more issues... If the calling client wants to program to an interface, i.e:



                            ResponseObjectProvider responseObjectProvider = new  GetObjectBySourceKeyResponseObjectProvider<>();


                            Then the addObject method will be available to the instance, but NOT the getParams and setParams methods of the ParametersProvider interface... To call these a cast is required, and to be safe an instanceof check should also be performed:



                            if(responseObjectProvider instanceof ParametersProvider) {
                            ((ParametersProvider)responseObjectProvider).setParams("identifier");
                            }


                            Not only is this undesirable it also breaks the Liskov Substitution Principle - "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program"



                            i.e. if we replaced an implementation of ResponseObjectProvider that also implements ParametersProvider, with an implementation that does not implement ParametersProvider then this could alter the some of the desirable properties of the program... Additionally, the client needs to be aware of which implementation is in use to call the correct methods



                            An additional problem is the usage for calling clients. If the calling client wanted to use an instance that implements both interfaces to perform addObject multiple times, the setParams method would need to be called before addObject... This could cause avoidable bugs if care is not taken when calling.



                            Solution Iteration 4 - Final Solution



                            The interfaces produced from Solution Iteration 3 solve all of the currently known usage requirements, with some flexibility provided by generics for implementation using different types. However, this solution breaks the Liskov Substitution Principle and has a non-obvious usage of setParams for the calling client



                            The solution is to have two separate interfaces, ParameterisedResponseObjectProvider and ResponseObjectProvider.



                            This allows the client to program to an interface, and would select the appropriate interface depending on whether the objects being added to the response require additional parameters or not



                            The new interface was first implemented as an extension of ResponseObjectProvider:



                            public interface ParameterisedResponseObjectProvider<T,S,U> extends ResponseObjectProvider<T, S> {
                            void setParams(U params);
                            U getParams();
                            }


                            However, this still had the usage issue, where the calling client would first need to call setParams before calling addObject and also make the code less readable.



                            So the final solution has two separate interfaces defined as follows:



                            public interface ResponseObjectProvider<T, S> {
                            void addObject(T targetObject, S sourceObject, String targetKey);
                            }


                            public interface ParameterisedResponseObjectProvider<T,S,U> {
                            void addObject(T targetObject, S sourceObject, String targetKey, U params);
                            }


                            This solution solves the breaches of Interface Segregation and Liskov Substitution principles and also improves the usage for calling clients and improves the readability of the code.



                            It does mean that the client needs to be aware of the different interfaces, but since the contracts are different this seems to be a justified decision especially when considering all the issues that the solution has avoided.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered 14 hours ago









                            jmljml

                            1375




                            1375






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54184354%2fhow-do-i-avoid-breaking-the-liskov-substitution-principle-with-a-class-that-impl%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                If I really need a card on my start hand, how many mulligans make sense? [duplicate]

                                Alcedinidae

                                Can an atomic nucleus contain both particles and antiparticles? [duplicate]