I have following code example (code below).
I have interfaces OnlyReverse and OnlySplit which define operations on class Data. I will sometimes have class available only for reversing and sometimes, I will be able to do reversing and splitting.
In the code I have 2 approaches.
1st approach is to use 2 separate classes for these 2 separate use-cases ReverseAndSplitImpl and OnlyReverseImpl. Here I do not like that I need additional class, and that I need to duplicate some of the code between those 2 classes.
2nd approach is to use 1 class for both use-cases SingleClassForReverseAndSplitImpl and then use strategy to inject either NormalSplit or NoSplit. Here I do not like this additional NoSplit class that is basically artificial one.
According to interface segregation principle - do I need to have ReverseAndSplit joining interface, or should I always use both interfaces separately (like SingleClassForReverseAndSplitImpl implements OnlyReverse, OnlySplit and not SingleClassForReverseAndSplitImpl implements ReverseAndSplit)?
Which approach of these is better in a long run (more flexible in the future)?
class Data{
String a;
}
interface OnlyReverse{
Data getData();
OnlyReverse reverse();
}
interface OnlySplit{
OnlySplit split();
}
interface ReverseAndSplit extends OnlyReverse, OnlySplit{
#Override
ReverseAndSplit reverse();
#Override
ReverseAndSplit split();
}
//------------------------- USE DISTINCT CLASSES; ONE HAS SPLIT OTHER NO
class ReverseAndSplitImpl implements ReverseAndSplit{
Data data;
public ReverseAndSplitImpl(Data data) {
this.data = data;
}
#Override
public Data getData() {
return data;
}
#Override
public ReverseAndSplit reverse() {
//here reverse and return
return new ReverseAndSplitImpl(data);
}
#Override
public ReverseAndSplit split() {
//here split and return
return new ReverseAndSplitImpl(data);
}
}
class OnlyReverseImpl implements OnlyReverse{
Data data;
public OnlyReverseImpl(Data data) {
this.data = data;
}
#Override
public Data getData() {
return data;
}
#Override
public OnlyReverse reverse() {
return new OnlyReverseImpl(data);
}
}
//------------------------- USE DISTINCT CLASSES; ONE HAS SPLIT OTHER NO
//------------------------- USE STRATEGY TO CHOOSE TO HAVE SPLITTING OR NO
interface SplitStrategy{
Data split(Data data);
}
class NormalSplit implements SplitStrategy{
#Override
public Data split(Data data) {
return new Data();
}
}
//NullObject pattern
class NoSplit implements SplitStrategy{
#Override
public Data split(Data data) {
return data;
}
}
class SingleClassForReverseAndSplitImpl implements ReverseAndSplit{
Data data;
SplitStrategy splitStrategy;
public SingleClassForReverseAndSplitImpl(Data data, SplitStrategy splitStrategy) {
this.data = data;
this.splitStrategy = splitStrategy;
}
#Override
public Data getData() {
return data;
}
#Override
public ReverseAndSplit reverse() {
//here reverse and return
return new SingleClassForReverseAndSplitImpl(data, splitStrategy);
}
#Override
public ReverseAndSplit split() {
//here split and return
SingleClassForReverseAndSplitImpl s = new SingleClassForReverseAndSplitImpl(data, splitStrategy);
s.data = splitStrategy.split(data);
return s;
}
}
//------------------------- USE STRATEGY TO CHOOSE TO HAVE SPLITTING OR NO
public class Decorator {
public static void main(String[] args) {
ReverseAndSplit s11 = new SingleClassForReverseAndSplitImpl(new Data(), new NoSplit());
s11 = s11.reverse();
s11 = s11.split(); //has split operation, but NoSplit will do nothing
OnlyReverse s12 = new OnlyReverseImpl(new Data());
s12 = s12.reverse();
//has no split operation present
//Going from NoSplit to SplitAndReverse
ReverseAndSplit s21 = new SingleClassForReverseAndSplitImpl(s11.getData(), new NormalSplit());
s21 = s21.reverse();
s21 = s21.split(); //has split and now it is using NormalSplit
ReverseAndSplit s22 = new ReverseAndSplitImpl(s12.getData());
s22 = s22.reverse();
s22 = s22.split();
}
}
I guess it's reasonable to use your first approach (two simpler interfaces) but to not call them OnlyReverse and OnlySplit but Reverse and Split. So it's reasonable to combine them and in future you can also just use one of them.
But it's also depending on your domain objects, so it's hard to make a choice for you. But I would not create an interface called NoSplit because you could still implement ReverseAndSplit and NoSplit which would make no sense for you.
According to the Interface Segregation Principle, if you have a client who never splits, then you should not present that client with an interface including a split method. The Strategy / Null Object approach is suitable for a single client who sometimes requires splitting and other times does not. The separate interfaces approach is suitable for two different clients who have different requirements.
Related
I have an OOP approach to calculating a special code. There is a list of strategies that uses the chain of responsibility approach to calculate my value;
interface ChainStrategy {
Strategy getNext();
String getCode(SomeDto dto);
default String getDefaultVlue() {
return "";
};
}
class StrategyA implements ChainStrategy {
Strategy next;
StrategyA() {}
StrategyA(Strategy next) {
this.next = next;
}
Strategy getNext() {
return next;
}
public String getCode(SomeDto dto) {
if(dto.isA()) {
String result = dto.getA();
//this code could be placed in the abstract class to fulfill DRY
if(result == null) {
if(next!=null) {
result = next.getCode(dto);
}
else {
result = getDefaultVlue();
}
}
return result;
}
}
class StrategyB implements ChainStrategy {
// mostly the same code with different result calculation logic
}
class Client {
ChainStrategy strategy = new StrategyA(new StrategyB());
System.out.println(strategy.getCode())
}
}
This is "Java < 8" code that meets SOLID principles and can be easily tested. Usually, the real logic is more complicated than just dto.getA()
But it is just a chain of functions so I rewrite it:
interface ChainStrategy {
String getCode(SomeDto dto);
}
class CombineStrategy implements ChainStrategy {
private static final Function<SomeDto, Optional<String>> STRATEGY_A = dto -> Optional.of(dto).filter(SomeDto::isA).map(SomeDto::getA());
private static final Function<SomeDto, Optional<String>> STRATEGY_B = dto -> Optional.of(dto).filter(SomeDto::isB).map(SomeDto::getB());
private static final Function<SomeDto, String> STRATEGY_DEFAULT = dto -> "";
String getCode(SomeDto dto) {
Stream.of(STRATEGY_A, STRATEGY_B).map(st->st.apply(dto))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElseGet(() -> STRATEGY_DEFAULT.apply(dto));
}
}
And my questions:
This code has problems with a single responsibility and "open-close" principles. And I can't test my functions individually. But creating separate classes for my functions looks like an overhead. Do we need these principles in functional programming?
I can rewrite "String getCode" to another static function. And store all these functions as a static Util class. But I don't want to lose ability to dynamically substitute my ChainFunction in the runtime. How do people combine static functions and dynamic binding in functional languages?
According to the SOLID principle open and close principle says class is open for extension and closed for modification.
So I am allowed to add new logic based on new if-else conditions?
If I will not use conditionals so how will I identify based on which condition which action has to be applied
public interface TemplateClassification {
QuesObj processTemplate(RawPart rawPart);
}
public class Template1 implements TemplateClassification{
#Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 1"+rawPart.getHead(),"Hi I am footer 1"+rawPart.getFoot());
}
}
public class Template2 implements TemplateClassification{
#Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 2"+rawPart.getHead(),"Hi I am footer "+rawPart.getFoot());
}
}
public class TemplateInfo {
private TemplateClassification templateClassification;
public TemplateClassification getTemplateClassification() {
return templateClassification;
}
public void setTemplateClassification(TemplateClassification templateClassification) {
this.templateClassification = templateClassification;
}
}
public class TemplateProduct {
public QuesObj calculateTemplate(TemplateInfo templateInfo,RawPart rawPart){
QuesObj ques = templateInfo.getTemplateClassification().processTemplate(rawPart);
return ques;
}
}
#RestController
class Pg {
#Autowired
TemplateInfo templateInfo;
#Autowired
TemplateProduct templateProduct;
public doProcessing(RawPart rawPart){
QuesObj ques = null;
if(rawPart.getId() == 1){
Template1 temp = new Template1();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(rawPart.getId() == 2){
Template2 temp = new Template2();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(tempId == 3){
// coming soon
}
}
}
How can i eliminte the if else condition so that it can follow open-close principle
To implement the "O" in SOLID, you can follow the below, which includes the "S" as well.
We are going to use polymorphism and inheritance.
Step 1 :
Create an interface that will sit in front of the classes that will be responsible in creating the QuesObj. We are going to need this, because down the line the code could receive a creator (child class) when id is 1,2 or 3.
It is important to note that QuesObj was identified because that is being returned on your original if statements and this is the reason we are allowed to continue with this approach.
public interface QuesObjCreator {
QuesObj calculate(RawPart rawPart);
}
Step 2:
Create individual class that creates the QuesObj in different ways in The only role of that class is to create the object.
public class QuesObjCreatorFor1 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
#Override
public QuesObj calculate(RawPart rawPart) {
Template1 temp = new Template1();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
public class QuesObjCreatorFor2 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
#Override
public QuesObj calculate(RawPart rawPart) {
Template2 temp = new Template2();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
Step 3:
Create a factory to return a QuesObjCreator. The factory will be returned to your main code/service.
public class QuesObjectCreatorFactory {
private static final Map<Integer,QuesObjCreator> quesObjCreatorMap = new HashMap<>();
public QuesObjectCreatorFactory() {
quesObjCreatorMap.put(1,new QuesObjCreatorFor1());
quesObjCreatorMap.put(2,new QuesObjCreatorFor2());
}
public static QuesObjCreator getQuesObjCreator(final int number) {
final QuesObjCreator quesObjCreator = quesObjCreatorMap.get(number);
if(quesObjCreator == null) {
throw new IllegalArgumentException("QuesObj for "+number+" does not exist");
}
return quesObjCreator;
}
}
Step 4:
Use Factory to create the QuesObj
public class Pg {
public void doProcessing(RawPart rawPart){
final QuesObjCreator quesObjCreator = QuesObjectCreatorFactory.getQuesObjCreator(rawPart.getId());
QuesObj ques = quesObjCreator.calculate(rawPart);
}
}
Collectively we achieved the Single responsibility across all classes and are decoupled.
It is easy to maintain cause now you can add more options to create QuesObj and none of the code would change, thus achieving open for extensibility/closed for modification.
It all boils down to the Factory and Map that has the creators. The map has to be populated with all the creator instances. With Spring this can be very easy, as Spring can scan your project, find beans of a specific type, give you a List and then you can convert it to a map.
Your case has nothing to do with SOLID. According to open-closed principle, you cannot allow modification to your class IN RUNTIME that can break its behavior.
In your case I suggest the following:
Add getId() method to your TemplateClassification interface.
Make each TemplateClassification implementation a bean
Add bean that will form the map of templates for you
#Bean
public Map<Integer, TemplateClassification> templates(List<TemplateClassification> templates) {
return algorithms.stream()
.collect(Collectors.toMap(TemplateClassification::getId, Function.identity()));
}
Autowire Map<Integter, TemplateClassification> templates to your controller and find the required template by id.
let's imagine the following situation: I want to design a bidding application (like ebay) with the composite design pattern
I create an abstract superclass like "BidComponent" (which has getName()) and two subclasses "Article" and "Category".
Category has a List which can contain other BidComponents, Article does not implement a List but a getPrice() method.
If I want to iterate through this structure and I want to print out the Category-Article-Structure I need instanceof:
if(element instanceof Article){
Article article = (Article)element;
System.out.println(article.getName() + ":" + article.getPrice());
}else{
Category category = (Category)element;
System.out.println(category.getName());
}
This seems pretty wrong to me. Is there a better way to realise this (So without always checking the type via instanceof)? I ask this question because I read several times that using instanceof is bad design...
//Edit to mention my problem with Visitors:
Ok. But let's imagine I want to search the highest bid to all products. So I have
public class HighestBidVisitor implements BidComponentVisitor{
private double highestBid = 0d;
public HighestBidVisitor(Category category){
visitCategory(category);
}
#Override
public void visitCategory(Category category){
Iterator<BidComponent> elementsIterator = category.iterator();
while(elementsIterator.hasNext()){
BidComponent bidComponent = elementsIterator.next();
//Now I have again the problem: I have to check if a component in the Categorylist is an article or a category
if(bidComponent instanceof Article) visitArticle((Article)bidComponent);
else visitCategory((Category)bidComponent);
}
}
#Override
public void visitArticle(Article article){
if(article.getPrice() > highestBid) highestBid = article.getPrice();
}
}
But now I have the same problem again (See comment in visitCategory). Or am I doing this wrong?
You want to use the visitor pattern.
public interface BidComponentVisitor {
void visitArticle(Article article);
void visitCategory(Category category);
}
Then your BidComponent class would have a visit method:
public abstract void visitChildren(BidComponentVisitor visitor);
The Composite and Visitor patterns often work together.
Edit: The key to avoiding instanceof when using the vistor pattern is how you implement the visitChildren method. In Category you would implement it like this:
#Override
public void visitChildren(BidComponentVisitor visitor) {
vistor.visitCategory(this);
for (BidComponent child : children) {
child.visitChidren(visitor);
}
}
Since Article has no children, it's implementation is simpler:
#Override
public void visitChildren(BidComponentVisitor visitor) {
vistor.visitArticle(this);
}
They key is each concrete class in the composite pattern knows it's own type, so it can call the specific visitor method that has a parameter with it's specific type.
One variation is to have enter and exit methods in the visitor for any class with children:
public interface BidComponentVisitor {
void visitArticle(Article article);
void enterCategory(Category category);
void exitCategory(Category category);
}
With the above interface, Category.visitChildren() would look like this:
#Override
public void visitChildren(BidComponentVisitor visitor) {
vistor.enterCategory(this);
for (BidComponent child : children) {
child.visitChidren(visitor);
}
vistor.exitCategory(this);
}
To print the tree, you could do something like this:
public class PrintingVisitor implements BidComponentVisitor {
private int depth = 0;
private void printIndent() {
for (int i = 0; i < depth; i++) {
System.out.print(" ");
}
}
public void visitArticle(Article article) {
printIndent();
System.out.println(article.toString());
}
public void enterCategory(Category category);
printIndent();
System.out.println(category.toString());
depth++;
}
public void exitCategory(Category category) {
depth--;
}
}
The disadvantage of the visitor patter is your visitor class needs to either hardcode every possible subclass, or have a generic visitOther() method.
You are doing the visitor implementation wrong. The different Components handle their own dispatching of elements. They know what type they are so you don't need to do any instanceof checks.
public interface Visitor{
void visit(Article a);
void visit(Category c);
}
abstract class BidComponent{
...
abstract void accept(Visitor v);
}
public class Category{
....
public void accept(Visitor v){
v.visit(this); // visit Category
for(Article a : getArticles()){
v.visit(a); //visit each article
}
}
}
Then a visitor to find the highest bid
public class HigestBidVisitor implements Visitor{
private final double highest;
void visit(Category c){
//no-op don't care
//or we could track which Category we have visited last
//to keep track of highest bid per category etc
}
void visit(Article a){
highest= Math.max(highest, a.getPrice());
}
}
Then to search all:
HigestBidVisitor visitor = new HighestBidVisitor();
BidComponent root = ...
root.accept(visitor);
double highest = visitor.getHighestPrice();
I can't think of any clean solution right now. You might have to update your implementation to either store Article and Category instances separately.
With your current implementation where a List<BidComponent> needs to be traversed and each element needs to be processed based on it's type, this approach can be a bit better:
abstract class BidComponent {
public abstract String process();
}
class Category extends BidComponent {
#Override
public String process() {
return getName();
}
}
class Article extends BidComponent {
#Override
public String process() {
return getName() + " " + getPrice();
}
}
List<BidComponent> list = ..;
for (BidComponent c : list) {
System.out.println(c.process());
}
Another way to decouple the processing logic from the classes/objects is:
Map<Class<?>, Function<BidComponent, String>> processors = new HashMap<>();
processors.put(Category.class, Category::getName());
processors.put(Article.class, a -> a.getName() + " " + a.getPrice());
List<BidComponent> list = ..;
for (BidComponent c : list) {
System.out.println(processors.get(c.getClass()).apply(c));
}
Note that this uses Java 8 lambdas but the same can be implemented with Java 7 or lower by using your own interface (similar to Function) or the ones provided by Guava or Apache Commons.
I have a string (which is a message) that I get as input and I need to do one of 4 possible things depending on the string
I know that there is eunm.valueOf() option, but I have 4 different enums, each with few possible messages.
looks something like:
public enum first{ONE,TWO,THREE};
public enum second{FOUR,FIVE,SIX};
public enum third{SEVEN,EIGHT,NINE};
public void work(String message){
//Here I want to compare message string to one of the 3 enums
}
is it possible to do this in one method of the enum?
or should I just try to create one, and if I get an exception try the other and so on?
As others have commented, it may be better to think through whether you really need 4 distinct enums.
But if you do, you could have them implement a common interface. Then you can map the input strings to the appropriate enum member, and call its method to accomplish what you want. Something like
public interface SomeInterface {
void doSomething();
};
public enum First implements SomeInterface {
ONE,TWO,THREE;
#Override
public void doSomething() { ... }
};
...
Map<String, SomeInterface> myMap = new HashMap<String, SomeInterface>();
for (First item : First.values()) {
myMap.put(item.toString(), item);
}
...
public void work(String message){
SomeInterface obj = myMap.get(message);
if (obj != null) {
obj.doSomething();
}
}
This assumes that the 4 possible things you want to do correspond to the 4 enums. If not, you can override the method separately for each and any enum member too, e.g.
public enum First implements SomeInterface {
ONE,
TWO {
#Override
public void doSomething() { // do something specific to TWO }
},
THREE;
#Override
public void doSomething() { // general solution for all values of First }
};
Enumerations in Java are full blown classes. Individual values can even override the behavior to meet their needs. It's pretty cool. You can use this to your advantage:
public enum Value implements Worker
{
ONE,
TWO,
THREE
{
#Override
public void doWork(String message)
{
// overrides behavior of base enum
}
},
FOUR,
/* ... */,
NINE;
private final String message;
Value() { this(""); }
Value(String message) { this.message = message; }
public void doWork(String message)
{
if (this.message.equals(message))
{
/* ... */
}
}
}
public interface Worker
{
void doWork(String message);
}
You can create a Map of them all
static final Map<String, Enum> enumMap = new LinkedHashMap<String, Enum>(){{
for(First e: First.values()) put(e.name(), e);
for(Second e: Second.values()) put(e.name(), e);
for(Third e: Third.values()) put(e.name(), e);
}};
Enum e = enumMap.get(name);
What you're really looking for is a aggregation of the other enums. The easiest way to get that is to make a new enum that puts all of those choices in a new enum. Something to this effect:
public enum Combination {
NEWONE(first.ONE), NEWTWO(first.TWO), NEWTHREE(first.THREE),
NEWFOUR(second.FOUR), NEWFIVE(second.FIVE), NEWSIX(second.SIX),
NEWSEVEN(third.SEVEN), NEWEIGHT(third.EIGHT), NEWNINE(third.NINE);
private String contents;
public Combination(first f) {
contents = f.toString();
}
public Combination(second s) {
contents = s.toString();
}
public Combination(third t) {
contents = t.toString();
}
public String toString() {
return contents;
}
}
This will more correctly aggregate the previous enums into a single data structure.
Even given your odd/even example in the comments, I don't feel multiple enums are the way to go here. I would use something like (warning, untested):
public enum Numbers {
ONE("first"), TWO("first"), THREE("first"), FOUR("second"), FIVE("second"), SIX("second"), SEVEN("third"), EIGHT("third"), NINE("third")
private String type;
Numbers(String t) { this.type = t; }
String getType { return this.type; }
}
Then you can use valueOf() to look up the enum element, and getType() to find out which of your three categories it belongs to.
It isn't entirely clear what you are asking, but perhaps you want to define a mapping between strings and constants, like this:
enum Type { FIRST, SECOND, THIRD };
Map<String, Type> mapping = new HashSet<String, Type>(){{
put("ONE", Type.FIRST);
put("TWO", Type.FIRST);
//...
put("NINE", Type.THIRD);
}};
public Type getTypeFromString(String s) {
return mapping.get(s);
}
I'm trying to define a class (or set of classes which implement the same interface) that will behave as a loosely typed object (like JavaScript). They can hold any sort of data and operations on them depend on the underlying type.
I have it working in three different ways but none seem ideal. These test versions only allow strings and integers and the only operation is add. Adding integers results in the sum of the integer values, adding strings concatenates the strings and adding an integer to a string converts the integer to a string and concatenates it with the string. The final version will have more types (Doubles, Arrays, JavaScript-like objects where new properties can be added dynamically) and more operations.
Way 1:
public interface DynObject1 {
#Override public String toString();
public DynObject1 add(DynObject1 d);
public DynObject1 addTo(DynInteger1 d);
public DynObject1 addTo(DynString1 d);
}
public class DynInteger1 implements DynObject1 {
private int value;
public DynInteger1(int v) {
value = v;
}
#Override
public String toString() {
return Integer.toString(value);
}
public DynObject1 add(DynObject1 d) {
return d.addTo(this);
}
public DynObject1 addTo(DynInteger1 d) {
return new DynInteger1(d.value + value);
}
public DynObject1 addTo(DynString1 d)
{
return new DynString1(d.toString()+Integer.toString(value));
}
}
...and similar for DynString1
Way 2:
public interface DynObject2 {
#Override public String toString();
public DynObject2 add(DynObject2 d);
}
public class DynInteger2 implements DynObject2 {
private int value;
public DynInteger2(int v) {
value = v;
}
#Override
public String toString() {
return Integer.toString(value);
}
public DynObject2 add(DynObject2 d) {
Class c = d.getClass();
if(c==DynInteger2.class)
{
return new DynInteger2(value + ((DynInteger2)d).value);
}
else
{
return new DynString2(toString() + d.toString());
}
}
}
...and similar for DynString2
Way 3:
public class DynObject3 {
private enum ObjectType {
Integer,
String
};
Object value;
ObjectType type;
public DynObject3(Integer v) {
value = v;
type = ObjectType.Integer;
}
public DynObject3(String v) {
value = v;
type = ObjectType.String;
}
#Override
public String toString() {
return value.toString();
}
public DynObject3 add(DynObject3 d)
{
if(type==ObjectType.Integer && d.type==ObjectType.Integer)
{
return new DynObject3(Integer.valueOf(((Integer)value).intValue()+((Integer)value).intValue()));
}
else
{
return new DynObject3(value.toString()+d.value.toString());
}
}
}
With the if-else logic I could use value.getClass()==Integer.class instead of storing the type but with more types I'd change this to use a switch statement and Java doesn't allow switch to use Classes.
Anyway... My question is what is the best way to go about something thike this?
What you are trying to do is called double dispatch. You want the method called to depend both on the runtime type of the object it's called on, and on the runtime type of its argument.
Java and other C derivatives support single dispatch only, which is why you need a kludge like the visitor pattern you used in option 1. This is the common way of implementing it. I would prefer this method because it uses no reflection. Furthermore, it allows you to keep each case in its own method, without needing a big "switchboard" method to do the dispatching.
I'd choose the second option, with the third, I'd better be using generics so you don't rely on that Enum. And with the first option you could be implementing methods for the rest of your life. Anyways you could use "instanceof" operator for Class matching.