Interface Segregation Principle - java

I'm learning SOLID principles with Java and I'm trying to implement two classes with this. My problem is about ISP. I have some methods that is present in one class but not in the other and I also have to refer both classes with the same interface.
This is the first class:
public final class Complex implements Number {
#Override
public String polarForm() {
//This class needs to implement this method
}
#Override
public String rectangularForm() {
//This class needs to implement this method
}
}
Here is the second one:
public final class Real implements Number {
#Override
public String polarForm() {
//This class does not need this method!
}
#Override
public String rectangularForm() {
//This class does not need this method!
}
}
Finally I have to refer to the classes something like this:
public static void main(String[] args) {
Number c = new Complex();
Number r = new Real();
Number n = c.add(r);
System.out.println(c.polarForm());
System.out.println(n);
}
How can I refer to both classes with the same interface without implementing unnecessary methods?

An alternate solution to approach this problem would be to use Composition instead of Inhertiance in conjunction to the interface segregation principle.
Number class
public class Number {
private RectangleForm rectangleForm;
private PolarForm polarForm;
private BigDecimal value;
public Number(RectangleForm rectangleForm, PolarForm polarForm,BigDecimal value) {
this.rectangleForm = rectangleForm;
this.polarForm = polarForm;
this.value = value;
}
public String polarForm() {
return polarForm.transform(this.value);
}
public String rectangleForm() {
return rectangleForm.transform(this.value);
}
//other methods such as add and subtract
}
PolarForm interface
public interface PolarForm {
public String transform(BigDecimal number);
}
RectangularForm interface
public interface RectangleForm {
public String transform(BigDecimal number);
}
RectangleForm implementation for real numbers
public class RectangleFormReal implements RectangleForm {
#Override
public String transform(BigDecimal number) {
String transformed = "";
//transfromed = logic to transform to rectangle form
return transformed;
}
}
PolarForm implementation for Real numbers
public class PolarFormReal implements PolarForm {
#Override
public String transform(BigDecimal number) {
//return the number as is without any transformation
return number.toString();
}
}
Putting the pieces together
public class NumberTest {
public static void main(String[] args) {
RectangleForm rf = new RectangleFormReal();
PolarForm pf = new PolarFormReal();
Number number = new Number(rf, pf,new BigDecimal(10));
String rectangleForm = number.rectangleForm();
String polarForm = number.polarForm();
}
}
You can create the PolarFormComplex and RectangleFormComplex implementations and wire theNumber instance in a similar fashion. The advantage of this approach is that your code will always rely on the interface of the Number class (by interface I mean the public APIs) and you can chose the transformation strategy by injecting the corresponding PolarForm or RectangleForm instances into your Number instance at compile time as shown above or at runtime (via a factory)

Break your Number interface (or base class) into multiple interfaces. The standard operations (add, subtract, etc) are in one; let's say INumber. polarForm and rectangularForm are part of another; let's say IComplex.
Real would implement INumber; Complex would implement INumber and Icomplex. You could then treat both as INumber.
If necessary, you could also create another interface that implements both.

Related

How to pass multiple Types that implement the same interface?

Firstly apologies about the not so great title, I am new to Java and wasn't sure how to title this.
I have a interface class "TestInterface":
ublic interface TestInterface {
String getForename();
void setForename(String forename);
String getSurname();
void setSurname(String surname);
}
"TestImpl" implements "TestInterface":
public class TestImpl implements TestInterface{
private String forename;
private String surname;
#Override
public String getForename() {
return forename;
}
public void setForename(String forename) {
this.forename = forename;
}
#Override
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
}
Then I have a call called "ExtendTest" which extends "TestImpl":
public class ExtendTest extends TestImpl{
private String firstLineAddress;
public String getFirstLineAddress() {
return firstLineAddress;
}
public void setFirstLineAddress(String firstLineAddress) {
this.firstLineAddress = firstLineAddress;
}
}
I then have this "Entity" class:
import java.util.List;
public class Entity {
private List<TestInterface> testInterfaces;
private List<ExtendTest> extendTests;
public List<TestInterface> getTestInterfaces() {
return testInterfaces;
}
public void setTestInterfaces(List<TestInterface> testInterfaces) {
this.testInterfaces = testInterfaces;
}
public List<ExtendTest> getExtendTests() {
return extendTests;
}
public void setExtendTests(List<ExtendTest> extendTests) {
this.extendTests = extendTests;
}
}
and finally this "DoStuff" class where the dostuff method accepts a parameter of type List
import java.util.List;
public class DoStuff {
public void doStuff(List<TestInterface> testData) {
}
}
I try to test this like so:
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
DoStuff doStuff = new DoStuff();
Entity entity = new Entity();
// Works
doStuff.doStuff(entity.getTestInterfaces());
// Does not work
doStuff.doStuff(entity.getExtendTests());
}
}
However where the comment is "Does not work" their is an error
Required type:
List<TestInterface>
Provided:
List<ExtendTest>
My question is how do I make it so that I can pass it in. My understanding was that becase they all implement TestInterface that it would work but I think I am wrong with this.
Thanks for any help and learnings here :)
You've run afoul of PECS. I recommend reading the linked answer for a more detailed explanation, but here's the bits specific to your use case.
When you have a generic type (List, in your case), if you only read from it, you should write List<? extends MyInterface>. If you only write to it, you should write List<? super MyInterface>. If you do both, then you want List<MyInterface>. Why do we do this? Well, look at your code.
public void doStuff(List<TestInterface> testData) { ... }
This function takes a List<TestInterface>. The List interface has a ton of capability. You can add and remove things to it in addition to just reading from it. And doStuff expects a list of TestInterface. So it's entirely fair game for the implementation of doStuff to do
testData.add(new ClassIJustMadeUp());
assuming ClassIJustMadeUp implements TestInterface. So we definitely can't pass this function a List<ExtendTest>, since that list type can't contain ClassIJustMadeUp.
However, if your function does only read from the list and isn't planning to add anything to it, you can write the signature as
public void doStuff(List<? extends TestInterface> testData) { ... }
and now you can pass a List of any type which extends TestInterface. It's fine to read from this list, since any type which extends TestInterface clearly can be upcast safely to TestInterface. But if we try to add a list element, that's a compiler error since the list doesn't necessarily support that particular type.

How to enable enum inheritance

I'm writing a library, which has a predefined set of values for an enum.
Let say, my enum looks as below.
public enum EnumClass {
FIRST("first"),
SECOND("second"),
THIRD("third");
private String httpMethodType;
}
Now the client, who is using this library may need to add few more values. Let say, the client needs to add CUSTOM_FIRST and CUSTOM_SECOND. This is not overwriting any existing values, but makes the enum having 5 values.
After this, I should be able to use something like <? extends EnumClass> to have 5 constant possibilities.
What would be the best approach to achieve this?
You cannot have an enum extend another enum, and you cannot "add" values to an existing enum through inheritance.
However, enums can implement interfaces.
What I would do is have the original enum implement a marker interface (i.e. no method declarations), then your client could create their own enum implementing the same interface.
Then your enum values would be referred to by their common interface.
In order to strenghten the requirements, you could have your interface declare relevant methods, e.g. in your case, something in the lines of public String getHTTPMethodType();.
That would force implementing enums to provide an implementation for that method.
This setting coupled with adequate API documentation should help adding functionality in a relatively controlled way.
Self-contained example (don't mind the lazy names here)
package test;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<HTTPMethodConvertible> blah = new ArrayList<>();
blah.add(LibraryEnum.FIRST);
blah.add(ClientEnum.BLABLABLA);
for (HTTPMethodConvertible element: blah) {
System.out.println(element.getHTTPMethodType());
}
}
static interface HTTPMethodConvertible {
public String getHTTPMethodType();
}
static enum LibraryEnum implements HTTPMethodConvertible {
FIRST("first"),
SECOND("second"),
THIRD("third");
String httpMethodType;
LibraryEnum(String s) {
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
static enum ClientEnum implements HTTPMethodConvertible {
FOO("GET"),BAR("PUT"),BLAH("OPTIONS"),MEH("DELETE"),BLABLABLA("POST");
String httpMethodType;
ClientEnum(String s){
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
}
Output
first
POST
Enums are not extensible. To solve your problem simply
turn the enum in a class
create constants for the predefined types
if you want a replacement for Enum.valueOf: track all instances of the class in a static map
For example:
public class MyType {
private static final HashMap<String,MyType> map = new HashMap<>();
private String name;
private String httpMethodType;
// replacement for Enum.valueOf
public static MyType valueOf(String name) {
return map.get(name);
}
public MyType(String name, String httpMethodType) {
this.name = name;
this.httpMethodType = httpMethodType;
map.put(name, this);
}
// accessors
public String name() { return name; }
public String httpMethodType() { return httpMethodType; }
// predefined constants
public static final MyType FIRST = new MyType("FIRST", "first");
public static final MyType SECOND = new MyType("SECOND", "second");
...
}
Think about Enum like a final class with static final instances of itself. Of course you cannot extend final class, but you can use non-final class with static final instances in your library. You can see example of this kind of definition in JDK. Class java.util.logging.Level can be extended with class containing additional set of logging levels.
If you accept this way of implementation, your library code example can be like:
public class EnumClass {
public static final EnumClass FIRST = new EnumClass("first");
public static final EnumClass SECOND = new EnumClass("second");
public static final EnumClass THIRD = new EnumClass("third");
private String httpMethodType;
protected EnumClass(String name){
this.httpMethodType = name;
}
}
Client application can extend list of static members with inheritance:
public final class ClientEnum extends EnumClass{
public static final ClientEnum CUSTOM_FIRST = new ClientEnum("custom_first");
public static final ClientEnum CUSTOM_SECOND = new ClientEnum("custom_second");
private ClientEnum(String name){
super(name);
}
}
I think that this solution is close to what you have asked, because all static instances are visible from client class, and all of them will satisfy your generic wildcard.
We Fixed enum inheritance issue this way, hope it helps
Our App has few classes and each has few child views(nested views), in order to be able to navigate between childViews and save the currentChildview we saved them as enum inside each Class.
but we had to copy paste, some common functionality like next, previous and etc inside each enum.
To avoid that we needed a BaseEnum, we used interface as our base enum:
public interface IBaseEnum {
IBaseEnum[] getList();
int getIndex();
class Utils{
public IBaseEnum next(IBaseEnum enumItem, boolean isCycling){
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
if (index + 1 < list.length) {
return list[index + 1];
} else if(isCycling)
return list[0];
else
return null;
}
public IBaseEnum previous(IBaseEnum enumItem, boolean isCycling) {
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
IBaseEnum previous;
if (index - 1 >= 0) {
previous = list[index - 1];
}
else {
if (isCycling)
previous = list[list.length - 1];
else
previous = null;
}
return previous;
}
}
}
and this is how we used it
enum ColorEnum implements IBaseEnum {
RED,
YELLOW,
BLUE;
#Override
public IBaseEnum[] getList() {
return values();
}
#Override
public int getIndex() {
return ordinal();
}
public ColorEnum getNext(){
return (ColorEnum) new Utils().next(this,false);
}
public ColorEnum getPrevious(){
return (ColorEnum) new Utils().previous(this,false);
}
}
you could add getNext /getPrevious to the interface too
#wero's answer is very good but has some problems:
the new MyType("FIRST", "first"); will be called before map = new HashMap<>();. in other words, the map will be null when map.add() is called. unfortunately, the occurring error will be NoClassDefFound and it doesn't help to find the problem. check this:
public class Subject {
// predefined constants
public static final Subject FIRST;
public static final Subject SECOND;
private static final HashMap<String, Subject> map;
static {
map = new HashMap<>();
FIRST = new Subject("FIRST");
SECOND = new Subject("SECOND");
}
private final String name;
public Subject(String name) {
this.name = name;
map.put(name, this);
}
// replacement for Enum.valueOf
public static Subject valueOf(String name) {
return map.get(name);
}
// accessors
public String name() {
return name;
}

Adding new implementations safely

I have interface and its implementations:
public interface SyntaxConstruction{
public String parseFromString(String str);
}
public class Copy implements SyntaxConstruction{
public String parseFromString(String str){ //impl };
}
public class Set implements SyntaxConstruction{
public String parseFromString(String str){ //impl };
}
I also have the following class:
public class Parser{
private static List<SyntaxElement> elementPrototypes; //should maintain the list of all implementation's prototypes
static{
//Initializing list with prtotypes of all possible SyntaxConstruction's implementations
}
public static List<SyntaxElement> parse(String str){
//getting syntax elements from str
}
}
Now we add a new implementation, say
public class Values implements SyntaxConstruction{
public String parseFromString(String str){ //impl };
}
If the user who add the class don't update the elementPrototypes list it may lead to hardly-catched bugs. I'd like to make them be awared of updating the list safely?
You could use an abstract implementation that "register" itself (in constructor) into Parser's elementPrototypes, something like:
public abstract class BaseSyntaxConstruction implements SyntaxConstruction {
protected BaseSyntaxConstruction() {
Parser.addElementPrototype(this);
}
}
public class Copy extends BaseSyntaxConstruction {
public String parseFromString(String str){
// impl
}
}
Note that you could also use reflection to "detect" SyntaxConstruction implementations
Following your comment, I think you might want to use an enum here to store implementations, no need to instantiate, no need to register (see values()):
enum SyntaxConstruction {
COPY {
#Override
public String parseFromString(String str){
// impl
}
},
// ...
;
public abstract String parseFromString(String str)
}

How can you call a class that is implementing a certain interface without knowing its name?

So I'm building a game engine and I need to be able to call methods from a class that implements a certain interface(I only want to call methods implemented by the interface).
My problem is that I don't know what the class name will be implementing it.
So how does, for instance, Java call the run() method in all classes that implement Runnable without knowing the class name?
Really, you're asking about the Factory pattern or a dependency injection container such as Spring.
Of course you can call the methods on an interface, the question is how you get the instance. That of course has to be specified, coded or configured somewhere. Configuration is preferable if there could ever be more than one in the future.
Thus, more of a real example:
public interface MovementStrategy {
public Move selectMove (Actor actor, ActorSituation theirSituation);
}
public class MonsterTypes {
public static MonsterType GOBLIN = new MonsterType( "goblin", new AttackMover(1.2));
public static MonsterType TROLL = new MonsterType( "troll", new AttackMover(0.45));
public static MonsterType DEER = new MonsterType( "deer", new FleeMover(2.0));
// useful to have, also.
public static List<MonsterType> getAllRegisteredTypes();
public static class MonsterType {
protected String name;
protected MovementStrategy moveStrategy;
// TODO -- getters & setters for all properties.
// constructor.
public MonsterType (String name, MovementStrategy moveStrategy) {
this.name = name;
this.moveStrategy = moveStrategy;
}
}
}
public class AttackMover implements MovementStrategy {
// SPEC: generally move towards/attack PC, with varying speeds.
}
public class FleeMover implements MovementStrategy {
// SPEC: generally run away from PCs.
}
This isn't probably a perfect design -- it conflates "movement" (aka goal-seeking) with the actor's turn/actions overall -- but hopefully it gives you some more idea.
If you only want to call methods from the interface (good!), then you usually don't need to now the name of the implementor.
getRunnableFromSomewhere().run();
always works and calls the run() method on the instance that is returned by that method.
If you want to now the class name at runtime, simpy call getClass().getName() on the instance:
System.out.println(getRunnableFromSomewhere().getClass().getName());
A simple example with the Number interface:
public class NumberExample {
public static void main(String[] args) {
MagicNumber magic = MagicNumberProvider.get(); // a random implementation
System.out.println(magic.getMagicNumber().doubleValue()); // We know nothing about the implementations
}
}
class MagicNumberProvider {
public static MagicNumber get() {
return Math.random() > 0.5d ? new ItsMagicOne() : new ItsMagicTwo();
}
}
interface MagicNumber {
public Number getMagicNumber();
}
class ItsMagicOne implements MagicNumber {
#Override
public Number getMagicNumber() {return new Long(1);}
}
class ItsMagicTwo implements MagicNumber {
#Override
public Number getMagicNumber() {return new Double(2.5);}
}
It only calls interface methods and we have, from the perspective of the main method, no idea, which implementation of MagicNumber is used (it's random) and on which implementation of Number we actually call the doubleValue() method.
Service Provide Interface
You can use java SPI (Service Provider Interface) by which later implementing jars declare the same service in the manifest. A using app can do a lookup, iterate over them and pick one.
An example is the different XML parser implementations.
Parameter
For your case it might suffice to have a run method:
class GameRunner {
public static void mainEntry(MyGameInterface mgi) {
}
}
And the implementors may do
cöass ThirdPartyGame implements MyGameInterface {
}
GameRunner.mainEntry(new ThirdPartyGame());
Plugin with java reflection
You can make your ad-hoc, self-define plugin emchanism, and use java reflection to instantiate the class. The third party jar must be placed at some location, that is in the class path, as defined in your jar's manifest. The class somewhere defined:
String klazz = resBundle.getProperty("pluginClass");
Class<MyGameInterface> klazz = Cass<MyGameInterface>.forName(klazz);
MyGameInterface game = klazz.getConstructor().newInstance();
If I understood your question correctly it seems you have slightly misunderstood polymorphism, you don't need to know the type that implements the interface.
See the following example, there is only one class that directly knows the types of each enemy, the initializing class.
import java.util.ArrayList;
import java.util.List;
public class SO18671999 {
public static interface Enemy {
public void Attack(Enemy other);
public String getName();
}
public static class Dragon implements Enemy {
String name = "Onyxia";
public void Attack(Enemy other) {
System.out.println(this.name + " attacks " + other.getName()
+ " for 10 dmg!");
}
public String getName() {
return this.name;
}
}
public static class Cerberus implements Enemy {
private String name;
private int dmg;
public Cerberus(String name, int dmg) {
this.name = name;
this.dmg = dmg;
}
#Override
public void Attack(Enemy other) {
System.out.println(this.name + " attacks " + other.getName()
+ " for " + this.dmg + " dmg!");
}
#Override
public String getName() {
return this.name;
}
}
public static class EnemyInitializer {
private List<Enemy> enemies;
public EnemyInitializer() {
enemies = new ArrayList<>();
enemies.add(new Dragon());
enemies.add(new Cerberus("CerberusHeadLeft", 10));
enemies.add(new Cerberus("CerberusHeadRight", 10));
enemies.add(new Cerberus("CerberusHeadCenter", 20));
}
public List<Enemy> getEnemies() {
return enemies;
}
}
public static class EnemyAttacker {
private EnemyInitializer eI = new EnemyInitializer();
public void startAttacking() {
List<Enemy> enemies = eI.getEnemies();
for (Enemy one : enemies) {
for (Enemy two : enemies) {
if (one == two)
continue;
one.Attack(two);
}
}
}
}
public static void main(String[] args) {
EnemyAttacker eAttacker = new EnemyAttacker();
eAttacker.startAttacking();
}
}

Access attribute of a subclass [duplicate]

This question already has answers here:
Check attribute of a subclass
(3 answers)
Closed 9 years ago.
I stumbled across that situation but I don't know how to handle it the right way:
class Coffee { }
class CoffeeMix extends Coffee {
public boolean shaken;
}
I'm saving the coffee items in an array list:
ArrayList<Coffee> coffees = new ArrayList<Coffee>();
So in this array list exist normal coffee objects and coffee mix objects. Now I want to display all coffee mix objects, that are shaken:
for(Coffee c : coffees) {
//here is the same problem as above
}
As I read in some answers on stackoverflow: instanceof seems to be a bad idea, because it screws the idea behind oo up. So how to handle this?
First of all, when we talk about OO we shouldn't use public fields.
I understand why you want to avoid to use instance of.
In this case you can use polymorphism and dynamic binding. You can add abstract isShaken method to the base class, make shaken as private at CoffeeMix and override isShaken (return shaken)
You should indeed use polymorphism. That is the best way to go here. But you want you can also use getclass en check if it equals the class that referring to.
You could use the Visitor pattern.
Here's an example how it could be applied to your case:
interface CoffeeElement {
void accept(CoffeeVisitor visitor);
}
interface CoffeeVisitor {
void visit(Coffee coffee);
void visit(CoffeeMix coffee);
}
class Coffee implements CoffeeElement {
private final String name;
public Coffee(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public void accept(CoffeeVisitor visitor) {
visitor.visit(this);
}
#Override
public String toString() {
return "Coffee [name=" + getName() + "]";
}
}
class CoffeeMix extends Coffee {
public CoffeeMix(String name) {
super(name);
}
#Override
public void accept(CoffeeVisitor visitor) {
visitor.visit(this);
}
#Override
public String toString() {
return "CoffeeMix [name=" + getName() + "]";
}
}
class PrintingCoffeeVisitor implements CoffeeVisitor {
#Override
public void visit(Coffee coffee) {
// ignore regular coffee
}
#Override
public void visit(CoffeeMix mix) {
System.out.println(mix);
}
}
class CoffeeTest {
public static void main(String[] args) {
List<Coffee> coffee = new ArrayList<Coffee>();
coffee.add(new Coffee("Java"));
coffee.add(new Coffee("Molokai"));
coffee.add(new CoffeeMix("Season Blend"));
CoffeeVisitor v = new PrintingCoffeeVisitor();
for (Coffee c : coffee) {
c.accept(v);
}
}
}
You can also read this explanation of the Visitor pattern. I found it very useful.
https://stackoverflow.com/a/2604798/467874
instanceof seems appropriate here, but if you really don't want to use it, you could try something ugly:
for (Coffee c : coffees) {
try {
CoffeeMix blend = (CoffeeMix) c;
//whatever you want to do with CoffeeMix objects
} catch (ClassCastException cce) {
//whatever you want to do with Coffee objects
}
}
This seems like a situation in which the cure is worse than the disease, but so long as CoffeeMix objects have some fields or properties which are unavailable to Coffee objects, the exception should be thrown, and you will have accomplished your class-wise sorting without having used instanceof at great cost to proper technique.

Categories

Resources