How to reduce if else jungle from my controller? - java

I have a java controller class, when ever save action is invoked in any item say Product or coverage or Limit , it calls the controller save method and a parameter is passed. The if logic in the controller checks the argument and call the save method of the appropriate object. The if logic is increasing day by day. Can any one suggest better design pattern?
Code:
public class Product {
public void save(PolicyData p){
//logic here
}
}
public class Coverage {
public void save(PolicyData p){
//logic here
}
}
public class Limit {
public void save(PolicyData p){
//logic here
}
}
public class Controller {
private Product pr=new Product();
private Limit lim=new Limit();
private Coverage cov=new Coverage();
public void save(PolicyData p,String item){
if(item.equals("Product")){
pr.save(p);
}if(item.equals("Coverage")){
cov.save(p);
}if(item.equals("Limit")){
lim.save(p);
}
}
}

Create a Saveable interface:
public interface Saveable {
public void save(String p);
}
your classes implement the interface, and then create a Map:
private Map<String, Saveable> saveMap = new HashMap<>();
Fill it with Savable objects and then call the save method based on the String.
public enum SaveableType {
PRODUCT, COVERAGE, LIMIT
}
public class Controller {
private Product pr = new Product();
private Limit lim = new Limit();
private Coverage cov = new Coverage();
private Map<SaveableType, Saveable> saveableMap = new HashMap<>();
public Controller() {
saveableMap.put(SaveableType.PRODUCT, pr);
saveableMap.put(SaveableType.LIMIT, lim);
saveableMap.put(SaveableType.COVERAGE, cov);
}
// better to use enum for the 2nd parameter not a String
public void save(PolicyData p, String item) {
SaveableType saveables = SaveableType.valueOf(item.toUpperCase());
saveableMap.get(saveables).save(p);
}
}

Create an interface that has save method
Implement the method in your object
In your controller create a map to hold objects against the key that you are comparing now in your if
code:
public interface Myinterface {
public void save(PolicyData p);
}
public class Product implements Myinterface{
public void save(PolicyData p){
//logic here
}
public class Controller {
private static HashMap<String,Myinterface> map=new HashMap<String,Myinterface>();
public Controller(){
map.put("Product", new Product());
map.put("Limit", new Limit());
map.put("Coverage", new Coverage());
}
public void save(PolicyData p,String item){
Myinterface m=map.get(item);
m.save(p);
}
}
}

Not really a solution to reduce the if-else jungle. But this might look more "beautiful".
http://www.w3schools.com/js/js_switch.asp
So in your case:
switch(item) {
case("Product"): pr.save(item); break;
// and so on...
}

Related

Question on diamond operator for design pattern strategy

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).

How to return a concrete implementation based on a variable(Enum/Object)

I was wondering how can I return a concrete implementation given a variable as argument in a function.
This is my test code
public interface Items {
String getName();
}
public class Car implements Items{
#Override
public String getName() {
return "Car";
}
public void drive(){
//To something
}
}
public class Shelf implements Items{
#Override
public String getName() {
return "Shelf";
}
public String getBooks(String bookName){
return bookName;
}
}
public enum Item {
CAR(Service::getCar),
TABLE(Service::getShelf),
;
Function<Service, ? extends Items> serviceFunction;
Item(Function<Service, ? extends Items> serviceFunction) {
this.serviceFunction = serviceFunction;
}
}
public class Service {
public Car getCar(){
return new Car();
}
public Shelf getShelf(){
return new Shelf();
}
public Items getItem(Item item){
return item.serviceFunction.apply(this);
}
public static void main(String[] args) {
Service service = new Service();
service.getItem(Item.CAR).getName();
// service.getItem(Item.CAR).drive(); // This is not valid.
}
}
So what I want is based on that enum I should be able to execute a set of functions related to that enum without passing the implementation identifier itself.
I know I can do this. And I will work but I was thinking of getting the concrete implementation without passing Class<T> klass.
public <T extends Items> T getItem(Item item, Class<T> klass){
return (T) item.serviceFunction.apply(this);
}
public static void main(String[] args) {
Service service = new Service();
service.getItem(Item.CAR, Car.class).drive();
}

How to pass down the new operator in a method

For example, if I wanted to do something like this to call a method:
myLights.addLight(new Fluorescent(lumens));
in order to create a new object in the Fluorescent class and pass down the lumens data. How would I then set up the method to receive this?
Assuming method is not returning anything.
void addlight(Fluorescent a){
// your logic
}
In your Lights class create a method that accepts a Fluorescent object as an argument.
public void addLight(Fluorescent fluorescent){
// do something
}
Here is a basic example:
public class HelloWorld
{
public static void main(String[] args)
{
Light light = new Light();
light.addLight(new Fluorescent("300 lm"));
System.out.print(light.getLumen());
}
}
public class Light {
private String lumen;
public Light() {
}
public void setLumens(String lumen){
this.lumen = lumen;
}
public String getLumen(){
return this.lumen;
}
public void addLight(Fluorescent fluorescent) {
if(fluorescent.getLumen() != null) {
this.lumen = fluorescent.getLumen();
}
}
}
public class Fluorescent {
private String lumen;
public Fluorescent(String lumen){
this.lumen = lumen;
}
public void setLumen(String lumen){
this.lumen = lumen;
}
public String getLumen(){
return this.lumen;
}
}
Seeing that a Fluorescent is a Light, you might want to look in to inheritance.
Look here for some explanation
Java 101: Inheritance in Java, Part 1
public class Fluorescent() {
public Fluorescent(String lumens) {
// do something
}
}
public class Lights() {
public void addLight(Fluorescent fluorescent) {
// do something
}
}

is it possible to check a variable with a list of method?

I want to pass a string into a series of method. These method will check whether the string have all properties needed. so, if the string didn't meet the requirement on one validator method, it will return false.
example :
input : "customerid=cu01","name=someone","phone=+628770xxxxx","address=somewhere","balance=500000"
output : true
another example :
"customerid=cu01","name=someone","address=somewhere","balance=200000"
output : false (no phone number)
Is it possible to create a list of validator class like this
List<Validator> val = new ArrayList<Validator>();
val.add(ValidatorA);
val.add(ValidatorB);
etc.
so i can check the string with that list of validator. i just want to know, is it possible to check a string with a list of validator like that? i'm doing this because it will be easier to add another validator if needed someday.
thanks
You could use the decorator pattern.
Take a look at this example I think it suits your usecase:
http://blog.decarufel.net/2009/09/using-decorator-or-wrapper-design.html
http://sourcemaking.com/design_patterns/decorator
public abstract class ValidationObject {
String description = "no particular";
public String getDescription(){
return description;
}
}
public class Account extends ValidationObject {
public Account(){
description = "account";
}
}
public class Book extends ValidationObject {
public Book () {
description = "book";
}
}
public abstract class ValidationObjectDecorator extends ValidationObject {
public abstract String getDescription();
}
public class ValidationOne extends ValidationObjectDecorator {
private ValidationObject account;
public ValidationOne (ValidationObject g) {
account = g;
}
#Override
public String getDescription() {
return account.getDescription() + "+ validationOneRan";
}
public void validateStuff() {
System.out.println("Big validation!");
}
}
We can add more method like "validateOtherStuff()" to each decorator without any limitations.
public class ValidationTwo extends ValidationObjectDecorator {
private ValidationObject book;
public ValidationTwo(ValidationObject g) {
book = g;
}
#Override
public String getDescription() {
return book.getDescription() + " ran validationTwo";
}
public void validationMethod() {
System.out.println("Big Validation!");
}
}
package designpatterns.decorator;
public class Main {
public static void main(String[] args) {
ValidationObject g1 = new Account();
System.out.println(g1.getDescription());
ValidationOne g2 = new Account(g1);
System.out.println(g2.getDescription());
ValidationTwo g3 = new Book(g2);
System.out.println(g3.getDescription());
}
}
Perhaps you can create an interface which will define a function such as "validate()", create implementations of this interface and then iterate over the list and apply the validate function.
Example:
public interface validator{
public boolean validate();
}
class validateUserName{
public boolean validate(){
return true;
}
}
class validatePhone{
public boolean validate(){
return false;
}
}
List<Validator> list = new ArrayList<Validator>();
list.add(new validPhone());
list.add(new validUserName());
for(Validator v : list)
v.validate();

How does Decorator pattern work in Java?

I was trying to understand Decorator Pattern. Below is the code am trying to understand how it works.
public static void main(String[] args)
{
Room myRoom = new CurtainDecorator(new ColorDecorator(new SimpleRoom()));
System.out.println(myRoom.showRoom());
}
Below is my Concrete Class
public class SimpleRoom implements Room{
#Override
public String showRoom()
{
return "show room";
}
}
Below is my abstract Decorator class
public abstract class RoomDecorator implements Room{
public Room roomReference;
#Override
public String showRoom()
{
return roomReference.showRoom();
}
}
Below is my Decorator implementation1
public class ColorDecorator extends RoomDecorator{
#Override
public String showRoom()
{
return addColors(); //How does showRoom() method gets invoked here?
}
public ColorDecorator(Room room)
{
this.roomReference = room;
}
public String addColors()
{
return "Blue";
}
}
Below is my Decorator implementation 2
public class CurtainDecorator extends RoomDecorator{
public CurtainDecorator(Room room)
{
this.roomReference = room;
}
#Override
public String showRoom()
{
return this.roomReference.showRoom() + addCurtains(); //What will showRoom method invoke?
}
public String addCurtains()
{
return "Curtain";
}
}
Output is - BlueCurtain
My question are placed in the comment..
In the end you have:
CurtainDecorator(ref=ColorDecorator(ref=SimpleRoom)))
When you call showRoom from main, it calls the method of CurtainDecorator, which in turn first goes to it's reference (ColorDecorator in this case) that outputs 'Blue', then CurtainDecorator adds it's bit 'Curtain'.

Categories

Resources