I got a problem where I am not allowed to use switch/case or if/else queries.
I got a config file I read which is this:
650;0;1.5;month
614;0;2.88;year
466;0;2.48;week
716;0;4.6;half-year
718;0;2.6;quarter
I am splitting those Strings at the ";", so it is saved in an array. The problem I have, that I need to do other things in the code for each time given in that array ar[3], so if it is a month I need other calculations then when it is a full year.
But I am not allowed to do this with Switch/case or If/Else, now I am getting confused.
If (ar[3] = month){
do this;
else if (ar[3] = year) {
do this;
}
How am I doing this object oriented? Thanks for every help :)
char, byte, short can be used in switches too.
Here are some alternatives to switch statement : lookup table. polymorphism. pattern matching (especially used in functional programming, C++ templates)
An if-then-else statement can test expressions based on ranges of values or conditions, whereas a switch statement tests expressions based only on a single integer, enumerated value, or String object. Technically, the final break is not required because flow falls out of the switch statement.
As it turns out, the switch statement is faster in most cases when compared to if-else , but significantly faster only when the number of conditions is large. The primary difference in performance between the two is that the incremental cost of an additional condition is larger for if-else than it is for switch .
As the name suggests, Object-Oriented Programming or OOPs refers to languages that uses objects in programming. Object-oriented programming aims to implement real-world entities like inheritance, hiding, polymorphism etc in programming.
You haven't mentioned if you can or do use Java 7. As of that java version you can use Strings in switch statements. Other than that, encapsulating the logic for each case is a good idea, for example: Department is of course in interface... Show activity on this post.
Object-oriented programming has several advantages over procedural programming: OOP helps to keep the Java code DRY "Don't Repeat Yourself", and makes the code easier to maintain, modify and debug
I must admit that it not only scatters tightly related code in multiple files (this is Java…), it’s unfortunately not always possible to easily apply OOP. In that case, it’s quite easy to initialise a map that returns the correct type.
It seems like you need some sort of inheritance structure based on the time period in ar[3]. The special do this
method could be coded for each case. That way you get the ability to do something different for each case. You just need a way to instantiate the correct subtype in the first place. There are a number of ways you could approach this.
The most direct approach IMHO is the conditional operator, ?:
.
So the code would look something like this:
MyClass x = ar[3].equals("month") ? new MyClassMonth() :
(ar[3].equals("year") ? new MyClassYear() :
(ar[3].equals("week") ? new MyClassWeek() :
(ar[3].equals("half-year") ? new MyClassHalfyear() :
new MyClassQuarter())));
x.doSomething();
The nested conditional expressions give you the ability to select the right class, and the inheritance gives you the polymorphic behavior you want.
But you mentioned in comment that you also can't use ?:
. What next?
Suppose you wrote MyClassMonth
in a way that nothing in it depended on any remembered state, i.e. the doSomething()
method has no side effects. Then you could create a Map<String, MyClass>
to store one instance of each subclass, then pull the relevant one out of the map when you needed to invoke.
You'd initialize the map like this:
final Map<String, MyClass> themap = new HashMap<>();
{
themap.add("month", new MyClassMonth());
themap.add("year", new MyClassYear());
themap.add("week", new MyClassWeek());
themap.add("half-year", new MyClassHalfyear());
themap.add("quarter", new MyClassQuarter());
}
And invoke doSomething()
with ar
as argument:
MyClass x = themap.get(ar[3]);
if (x != null)
x.doSomething(ar);
There are other ways to do this. Sticking with the Map
concept, you could store class literals in the Map
instead of instances, then instantiate them reflectively. You could also keep a lambda in the Map
and invoke it.
@OldCurmudgeon suggested using enums. If you put those enums into the Map
and add a lambda to the enum, you can grab the enum and invoke the lambda. That would work and has a certain appeal, but it seems unnecessary. You'd be better off just invoking the lambda directly.
You could use an enum
as a command factory pattern and implement the choice with a Map
lookup.
// Lookups for teh period.
static final Map<String, Period> lookup = new HashMap<>();
enum Period {
Month("month") {
@Override
void process(int x, int y, double v) {
// Processing for "month" records here.
System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
}
},
Year("year") {
@Override
void process(int x, int y, double v) {
// Processing for "year" records here.
System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
}
},
Quarter("quarter") {
@Override
void process(int x, int y, double v) {
// Processing for "quarter" records here.
System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
}
},
HalfYear("half-year") {
@Override
void process(int x, int y, double v) {
// Processing for "half-year" records here.
System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
}
};
Period(String inData) {
// Record me in the map.
lookup.put(inData, this);
}
abstract void process(int x, int y, double v);
static void process(String data) {
String[] parts = data.split(";");
Period p = lookup.get(parts[3]);
if (p != null) {
p.process(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Double.parseDouble(parts[2]));
}
}
}
public void test() {
String[] test = {"650;0;1.5;month",
"614;0;2.88;year",
"466;0;2.48;week",
"716;0;4.6;half-year",
"718;0;2.6;quarter",};
for (String s : test) {
Period.process(s);
}
}
correctly prints:
Month-process(650,0,1.5)
Year-process(614,0,2.88)
HalfYear-process(716,0,4.6)
Quarter-process(718,0,2.6)
Note that there is one if
in there but that is only defensive to avoid bad data - it is not part of the lookup mechanism.
Something like this:
public interface Calculator {
double calculate(int p1, int p2, double p3);
}
public class YearCalculator implements Calculator {
public double calculate(int p1, int p2, double p3) {
double value = 0.0;
// do year calculations
return value;
}
}
public class CalculatorFactory {
public Calculator getInstance(String type) {
Calculator calculator = null;
if (type != null) {
} else {
throw new IllegalArgumentException("calculator type cannot be null");
if ("year".equalsIgnoreCase(type)) {
} else {
System.out.println(String.format("No such type: %s", type));
}
}
return calculator;
}
}
You have to have if/else logic in the factory, but not when you're parsing the text.
Your processing code:
CalculatorFactory factory = new CalculatorFactory();
// contents is a List of Strings from your input file.
for (String line : contents) {
String [] tokens = line.split(";");
Calculator calculator = factory.getInstance(tokens[3]);
double value = calculator.calculate(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1]), Double.parseDouble(tokens[2]));
}
Building upon the suggestion given by Codebender as an alternative solution:
You need 5 classes, one for each case, with a common interface but different implementations.
Your interface may look something like this:
public interface MyCalculator {
public double calculate(double a, double b, double c);
}
Then you will need to implement your 5 classes similar to this. You will need a different class with a different implementation for calculate
for month
, year
, week
, half-year
and quarter
:
public class MyMonthCalculator implements MyCalculator {
@Override
public double calculate(double a, double b, double c) {
// Do your calculations here then return
}
}
Then, before your parsing logic, you can add the five classes to a Map
.
map.put("month", new MyMonthCalculator());
// Repeat for year, week, half-year and quarter
To actually perform a calculation:
double result = map.get(ar[3]).calculate(Double.parseDouble(ar[0]), Double.parseDouble(ar[1]), Double.parseDouble(ar[2]));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With