I'm wondering if the Interface segregation principle applys to my codebase.
Here's some example code:
First Class:
public class EntityGroup {
public List<Entity> tests;
//returns true if the EntityGroup is valid
public boolean validate() {
for (Entity test : tests) {
if (!test.validateFieldA() || !test.validateFieldB()) {
return false;
}
}
return true;
}
}
Second Class:
public abstract class Entity {
protected String fieldA;
public abstract boolean validateFieldA();
public abstract boolean validateFieldB();
}
Third Class:
public class EntityChild extends Entity {
private String fieldB;
#Override
public boolean validateFieldA() {
if (fieldA.equals("valid")) {
return true;
} else {
return false;
}
}
#Override
public boolean validateFieldB() {
if (fieldB.equals("valid")) {
return true;
} else {
return false;
}
}
}
Fourth Class:
public class EntityChild2 extends Entity {
#Override
public boolean validateFieldA() {
if (fieldA.equals("valid")) {
return true;
} else {
return false;
}
}
#Override
public boolean validateFieldB() {
return true;
}
}
This is a greatly simplified example from my real codebase but I think it illustrates the problem well. My EntityChild2 class is forced to implement a method it does not need or want to know about.
I know that it would be more correct to have a Interface that would contain the validateFieldB() method and only have EntityChild implement that interface.
With the understanding that this would take a significant amount of effort to refactor into this solution, I'm having a hard time justifying the time it would take to implement this solution in my real code base.
What potential problems will I run into down the line by leaving my code this way?
What benefits will I gain from refactoring my code to have a separate interface for validateFieldB()?
tldr: Why is the Interface Segregation Principle so important?
Wrong Abstraction
You make use of the interface segregation principle but with wrong abstractions.. Your different Entity-types differ only in they behavior.
Because of the shared behavior you have duplicate code in the methods validateFieldA of EntityChild and EntityChild2 . The method validateFieldB looks very similar to validateFieldA just the filed for checking the equality is an other.
You only need one Entity
Strategy Pattern
With the Strategy-Pattern you will have no duplicate code:
class EqualValidationStategy() implements ValidationStategy<T> {
#Override
public boolean check(T a, T b) {
return a.equals(b)
}
}
class TrueValidationStategy() implements ValidationStategy<T> {
#Override
public boolean check(T a, T b) {
return true;
}
}
Entity
public class Entity {
private String fieldA;
private String fieldB;
private ValidationStategy<String> validationForA;
private ValidationStategy<String> validationForB;
// all-args consturctor
#Override
public boolean validateFieldA() {
return validationForA.check(fieldA, "valid");
}
#Override
public boolean validateFieldB() {
return validationForB.check(fieldB, "valid");
}
}
// Validates fieldA and "ignores" fieldB
Entity example = new Entity(fieldA,
fieldB,
new EqualValidationStategy(),
new TrueValidationStategy());
Related
Small question regarding the diamond operator and design pattern strategy for Java, please.
I would like to implement a very specific requirement:
there are some objects to store (in my example called MyThingToStore)
and the requirement is to store them with different kinds of data structures, for comparison.
Therefore, I went to try with a strategy pattern, where each of the strategies is a different way to store, I think this pattern is quite lovely.
The code is as follows:
public class MyThingToStore {
private final String name;
public MyThingToStore(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyThingToStore that = (MyThingToStore) o;
return Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "MyThingToStore{" +
"name='" + name + '\'' +
'}';
}
}
public class MyStorage {
private final StorageStrategy storageStrategy;
public MyStorage(StorageStrategy storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
public interface StorageStrategy {
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy{
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And this is working fine, very happy, especially tackled the requirement "easy to change the data structure to do the actual store".
(By the way, side question, if there is an even better way to do this, please let me know!)
Now, looking online at different implementations of strategy patterns, I see this diamond operator which I am having a hard time understanding:
MyThingToStore stays the same.
public class MyStorage {
private final StorageStrategy<MyThingToStore> storageStrategy; //note the diamond here
public MyStorage(StorageStrategy<MyThingToStore> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
#Override
public String toString() {
return "MyStorage{" +
"storageStrategy=" + storageStrategy +
'}';
}
}
public interface StorageStrategy<MyThingToStore> {
//note the diamond, and it will be colored differently in IDEs
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy<MyThingToStore> {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy<MyThingToStore> {
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy<MyThingToStore> storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And both versions will yield the same good result, also be able to answer requirements.
My question is: what are the differences between the version without a diamond operator, and the version with the diamond operator, please?
Which of the two ways are "better" and why?
While this question might appear to be "too vague", I believe there is a reason for a better choice.
I think the confusion comes from how you named type parameter for StorageStrategy in your 2nd example.
Let's name it T for type instead. T in this case is just a placeholder to express what type of objects your StorageStrategy can work with.
public interface StorageStrategy<T> {
void addToStore(T myThingToStore);
int getSize();
}
E.g.
StorageStrategy<MyThingToStore> strategy1 = // Initialization
StorageStrategy<String> strategy2 = // Initialization
strategy1.addToStore(new MyThingToStore("Apple"));
// This works fine, because strategy2 accepts "String" instead of "MyThingToStore"
strategy2.addToStore("Apple");
// Last line doesn't work, because strategy1 can only handle objects of type "MyThingToStore"
strategy1.addToStore("Apple");
To make it work properly, you need to change your different StorageStrategy implementations to also include the type parameter.
public class StorageUsingHashSetStrategy<T> implements StorageStrategy<T> {
private final Set<T> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(T myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
And lastly you also want to have a type paremeter for MyStorage
public class MyStorage<T> {
private final StorageStrategy<T> storageStrategy;
public MyStorage(StorageStrategy<T> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(T myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
Now you can create a MyStorage and can use it to store essentially any object into it and not just MyThingToStore. Whether that is something you want or not is up to you.
In the second code sample in the declaration of the interface StorageStrategy<MyThingToStore>, MyThingToStore is a Type Variable.
I.e. it's not the actual type, only a placeholder for a type, like T. The common convention is to use single-letter generic type variables (T, U, R, etc.), otherwise it might look confusing like in this case.
Note that in the class declarations, like:
public class StorageUsingArrayListStrategy
implements StorageStrategy<MyThingToStore>
MyThingToStore is no longer a type variable, but the name of the class MyThingToStore because in this case parameterized interface is implemented by a non-parameterized class (i.e. the actual type known to the compile is expected to be provided).
I ran into a bit of an issue and was hoping someone could tell me what I'm missing here.
for some context I have the following methods:
private boolean windowork;
public class WinidowMalfunction extends Event {
ControllerException newException = new ControllerException("Error:");
public WinidowMalfunction(long delayTime) {
super(delayTime);
}
public void action() throws ControllerException {
windowork = false;
someThingWentWrongHere(1, "Error at WinidowMalfunction");
}
}
private boolean poweron;
public class PowerOut extends Event {
public PowerOut(long delayTime) {
super(delayTime);
}
public void action() throws ControllerException {
poweron = false;
someThingWentWrongHere(2, "Error at powerOut event");
}
}
and I'm creating interface Fixable where I need to change the value of poweron and windowork to change their values to true. but I can't get the FIxable to accept the references. they are all in the same class so is there a way to reference these boolean function in an interface
EDIT:
Assignment question:
In this part, we add functionality for restoring the saved GreenhouseControls object and having it resume execution where it left off. It demonstrates the use of interfaces and the capability of Java methods to return objects.
Create the following interface
interface Fixable {
// turns Power on, fix window and zeros out error codes
void fix ();
// logs to a text file in the current directory called fix.log
// prints to the console, and identify time and nature of
// the fix
void log();
}
You can do something like this:
interface Fixable {
public boolean setTrue();
}
class Foo implements Fixable {
private boolean windowork = false;
public void setTrue() {
windowork = true;
}
}
class Bar implements Fixable {
private boolean poweron = false;
public void setTrue() {
poweron = true;
}
}
The only advantage of the above is if you had an array of Fixable objects you could iterate thru them and do this.
for (Fixable f : fixableArray) {
f.setTrue();
}
An interface can be designed in a way to read-write a boolean property that resides in the class/instance.
public interface Somename {
public boolean isPowerOn();
public void setPowerTo(boolean arg);
}
I want to check if all the ingredients(toppings and fillings) inside a wrap are both vegan and nut free. This is the solution that I came up with, howver I think its a bit inefficient as there is duplication of code. Is there a more efficient way to do it?
(I have a map for all the toppings and fillings which every one contains boolean to know if the topping/filling is vegan and if it is nut free.
public boolean isVegan() {
for (Topping t : toppings) {
if (!t.isVegan()) {
return false;
}
}
for (Filling f : fillings) {
if (!f.isVegan()) {
return false;
}
}
return bread.isVegan();
}
public boolean isNutFree() {
for (Topping t : toppings) {
if (!t.isNutFree()) {
return false;
}
}
for (Filling f : fillings) {
if (!f.isNutFree()) {
return false;
}
}
return bread.isNutFree();
}
Supposing that Ingredient is the base class of these different classes and that this class defines the isVegan() method, you could create a Stream from all these objects and computing whether all are vegan :
public boolean isVegan() {
return
Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
.allMatch(Ingredient::isVegan);
}
For isNutFree() the idea is the same :
public boolean isNutFree() {
return
Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
.allMatch(Ingredient::isNutFree);
}
Note that you could also generalize a matching method to reduce further the duplication :
public boolean allMatch(Predicate<Ingredient> predicate) {
return
Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
.allMatch( i -> predicate.test(i));
}
And use it such as :
boolean isNutFree = allMatch(Ingredient::isNutFree);
boolean isVegan = allMatch(Ingredient::isVegan);
Here is a food type replacing either Topping or Filling or anything:
public interface FoodPart {
boolean isVegan();
boolean isNutFree();
}
Here we have an abstract Food class containing all common codes:
public abstract class Food {
private List<? extends FoodPart> foodParts;
public boolean isVegan() {
return foodParts.stream().noneMatch(foodPart -> foodPart.isVegan());
}
public boolean isNutFree() {
return foodParts.stream().noneMatch(foodPart -> foodPart.isNutFree());
}
}
And here is a concrete and not abstract food:
public class Lasagne extends Food {}
Edit:
If you don't want to inherit from FoodPart then you can change List<? extends FoodPart> simply to List<FoodPart>.
You can also make Food to not abstract so you can easily use it, and don't forget to add getters/setters to provide the foodParts.
Yeez, you guys are fast :)
What I wrote is pretty much already covered in the other answers here but just posting since mine does have some subtle differences (not necessarily better). And since I already went through the motions of writing the code I might as well post it :)
First an interface for your fillings and toppings:
public interface FoodInformation {
boolean isVegan();
boolean isNutFree();
boolean isGlutenFree();
}
Then an abstract class which your toppings and fillings can extend:
public abstract class Ingredient implements FoodInformation {
private boolean vegan;
private boolean nutFree;
private boolean glutenFree;
public Ingredient(boolean vegan, boolean nutFree, boolean glutenFree) {
this.vegan = vegan;
this.nutFree = nutFree;
this.glutenFree = glutenFree;
}
#Override
public boolean isVegan() {
return vegan;
}
#Override
public boolean isNutFree() {
return nutFree;
}
#Override
public boolean isGlutenFree() {
return glutenFree;
}
}
Your Filling:
public class Filling extends Ingredient {
public Filling(boolean vegan, boolean nutFree, boolean glutenFree) {
super(vegan, nutFree, glutenFree);
}
}
Your Topping:
public class Topping extends Ingredient {
public Topping(boolean vegan, boolean nutFree, boolean glutenFree) {
super(vegan, nutFree, glutenFree);
}
}
And your Wrap:
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class Wrap {
private List<Filling> fillings;
private List<Topping> toppings;
public Wrap(List<Filling> fillings, List<Topping> toppings) {
this.fillings = fillings;
this.toppings = toppings;
}
public boolean isNutFree() {
return testIngredient(FoodInformation::isNutFree);
}
public boolean isVegan() {
return testIngredient(FoodInformation::isVegan);
}
public boolean isGlutenFree() {
return testIngredient(FoodInformation::isGlutenFree);
}
private boolean testIngredient(Predicate<FoodInformation> predicate) {
// edited thanks to davidxxx for the Stream.concat notation!
return Stream
.concat(fillings.stream(), toppings.stream())
.allMatch(predicate);
}
}
And a test to show the implementation works:
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;
public class WrapTest {
private Wrap wrap;
#Before
public void setup() {
Filling filling1 = new Filling(true, true, false);
Filling filling2 = new Filling(true, false, true);
Filling filling3 = new Filling(true, true, true);
Topping topping1 = new Topping(true, true, true);
wrap = new Wrap(Arrays.asList(filling1, filling2, filling3), Collections.singletonList(topping1));
}
#Test
public void testIsGlutenFree() {
assertFalse(wrap.isGlutenFree());
}
#Test
public void testIsNutFree() {
assertFalse(wrap.isNutFree());
}
#Test
public void testIsVegan() {
assertTrue(wrap.isVegan());
}
}
Have fun with your project!
create an interface that has isVegan and isNutFree
public interface MyInterface {
boolean isVegan();
boolean isNutFree();
}
Then each of your classes with implement your interface
public class Topping implements MyInterface {
#Override
public boolean isVegan() {
return isVegan;
}
#Override boolean isNutFree() {
return isNutFree;
}
}
public class Filling implements MyInterface {
#Override
public boolean isVegan() {
return isVegan;
}
#Override boolean isNutFree() {
return isNutFree;
}
}
Next create a method that can test the lists
public boolean isVegan(List<? extends MyInterface> list) {
for(MyInterface myObj : list) {
if (myObj.isVegan()) return true;
}
return false;
}
public boolean isNutFree(List<? extends MyInterface> list) {
for(MyInterface myObj: list) {
if (myObj.isNutFree()) return true;
}
return false;
}
then each list you can pass into the methods to get the results
I try create Payment by strategy pattern. But All articles each I read look like this:
public interface PayStrategy {
void pay(BigDecimal paymentAmount);
}
But if I need return Single<RestResponse<PaymentResponse>>?Is this the right approach?
public interface PayStrategy {
Single<RestResponse<PaymentResponse>> pay(BigDecimal paymentAmount);
}
In any real system, the request for payment will return the result
I will suggest you to implement your problem statement in Generic return type like below:
public interface IPayStrategy<T> {
T Pay();
}
public class PayStrategy1 :IPayStrategy<int> {
public int Pay() { }
}
public class PayStrategy2 :IPayStrategy<String> {
public String Pay() { .. }
}
public class Context<T> {
private IPayStrategy<T> payStrategy;
public setStrategy(IPayStrategy<T> strategy) { this.payStrategy = strategy; }
public T doPayment() {
return payStrategy.Pay();
}
}
in my opinion it's right because it's up to you the definition of the contract, if you agree that all the strategies must return a result that is of type Single<RestResponse<PaymentResponse>> for me it's correct
I have class with 2 states which are defined by the value of an attribute (e.g. started that can be true of false)
When I call a method from an instance I want to get a different behaviour depending on the state.
I'm currently using an if statement that will query for the state every time the method is called but I think that there might be a quicker way to do this (something like polymorphism maybe?)
Is there an elegant way to implement this? I've thought of having two subclasses inherinting and casting them when the behave changes but maybe there's something better
A dummy example below (my actual problem is much more time consuming and hence the need for improvement)
public class StateChangingClass {
private boolean started;
public StateChangingClass() {
started = false;
}
public void start(){started = true;}
public void end(){started = false;}
public boolean checkCondition(double time) {
if (started) {
if (time>0) {return true;}
else {return false;}
}
else {return false;}
}
}
In this example it is way too much, but maybe you get an idea of how you can use it in your situation. I have added an interface 'ConditionChecker' which has two implementations. The Methods 'start' and 'end' just set the needed ConditionChecker.
public class StateChangingClass {
private ConditionChecker conditionChecker;
public StateChangingClass() {
conditionChecker = StartedChecker.INSTANCE;
}
public void start() {
conditionChecker = StartedChecker.INSTANCE;
}
public void end() {
conditionChecker = EndChecker.INSTANCE;
}
public boolean checkCondition(double time) {
return conditionChecker.check(time);
}
interface ConditionChecker {
boolean check(double time);
}
static class StartedChecker implements ConditionChecker {
public static final ConditionChecker INSTANCE = new StartedChecker();
#Override
public boolean check(double time) {
return (time > 0);
}
}
static class EndChecker implements ConditionChecker {
public static final ConditionChecker INSTANCE = new EndChecker();
#Override
public boolean check(double time) {
return false;
}
}
}