How can I improve this block of code? - java

public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
Double discountAmount = 0.0;
switch (discountCode) {
case 'A':
discountAmount = 0.95 * itemTotal;
break;
case 'B':
discountAmount = 0.15 * itemTotal;
break;
}
return itemTotal - discountAmount;
}
Current implementation in order processor is closed for extension and open for modification for adding new discount codes, how can i improve the design to get rid of this limitation

In general, the presence of a switch is a pretty good giveaway as to what should be a class instead. So, a first stab at it would be something like this:
public interface Discounter {
public double applyDiscount(double itemTotal);
}
public class OrderProcessor {
private Map<Char, Discounter> discounts = new HashMap<Char, Discounter>();
public void addDiscounter(Char discountCode, Discounter discounter) {
discounts.put(discountCode, discounter);
}
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
double itemTotal = order.getItemTotal();
double discountAmount = 0.0;
if (discounts.hasKey(discountCode))
discountAmount = discounter.applyDiscount(itemTotal);
return itemTotal - discountAmount;
}
}
This would then be extended through something like this:
processor.addDiscounter('A', new Discounter() {
public double applyDiscount(double itemTotal) {
return 0.95 * itemTotal;
}
});
You could make a remove method as well, and then your discounters can become more complex, consulting external data, etc. You may want to open up the interface a bit and pass in the whole order for more examination.
Note: If this is something you're going to be doing in production I have two pieces of unsolicited advice:
Consider using something like JBoss Drools to handle your business logic instead of this; it's a lot more powerful and flexible.
Please don't use double for actual financial calculations. :)

As you have pointed out that the discount code needs to be changeable, it is best to separate out the actual discount codes from the code. Maintain the discount codes in an xml or settings file and lazy load the values into a dictionary/hashset before using them.
For example your xml could look like this,
<Discounts>
<Discount code="A" value="0.05"/>
<Discount code="B" value="0.10"/>
<Discount code="C" value="0.15"/>
</Discounts>
In your calculateTotalPriceWithDiscountCode, populate a dictionary with the values read from this xml.
if(discountsDictionary == null)
{
discountsDictionary = LoadValuesFromXml(xmlFilePath);
}
In case your discounts xml is likely to change during program execution then perform the Load operation when you want the discount value (as compared to loading once in the above code fragment).
Then access the code (key) to retrieve the discount (value),
if(discountsDictionary.ContainsKey(discountCode))
{
discount = discountsDictionary[discountCode];
discountedItemPrice = itemPrice * ( 1 - discount);
}
else
{
// Invalid discount code...
}

Pull the logic for calculating totals based on an order into its own class/interface:
class OrderProcessor {
// Probably inject this or load it some other way than a static factory
private Collection<TotalCalculator> calculators = TotalCalculatorFactory.getTotalCalculators();
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
for (TotalCalculator calculator : calculators) {
if (calculator.supports(discountCode)) {
return calculator.calculateTotal(order);
}
}
return order.getItemTotal();
}
}
class TotalCalculator {
private char discountCode;
private double discountRatio;
public TotalCalculator(char discountCode, double discountRatio) {
this.discountCode = discountCode;
this.discountRatio = discountRatio;
}
public boolean supports(char discountCode) {
return this.discountCode == discountCode;
}
public Double calculateTotal(Order order) {
return order.getItemTotal() - order.getItemTotal() * discountRatio;
}
}
class TotalCalculatorFactory {
public static Collection<TotalCalculator> getTotalCalculators() {
return Arrays.asList(
new TotalCalculator('A', 0.95),
new TotalCalculator('B', 0.15)
);
}
}
In a real system, I'd make the TotalCalculator an interface, which would have the additional advantage of being able to calculate order totals in other ways than just a percentage discount reduction.
This solution is also very flexible in allowing you to create your TotalCalculators (or implementations if an interface) using other mechanisms than manually coding them into a factory. You can use an IoC container to create and inject them or use a ServiceLoader to find and load them, for example.

My idea is maintain discounts separately.
public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
return itemTotal - (itemTotal* Discounts.GetDiscounts(discountCode));
}
}
////////////////
class Discounts
{
public static double GetDiscounts(char discountCode)
{
switch (discountCode) {
case 'A':
return 0.95d;
case 'B':
return 0.15d;
default:
return 0.00d;
}
}
}

In this calculateTotalPriceWithDiscountCode function, it is not a good idea to pass a discount code as parameter. Well, 3rd person , who review your code , would not understand would not understand what does it mean except you, a kind of code smell.
One of a suggestion is that you need to create another class called Discount, and you pass the Discount object as a parameter, and you get the internal value from its public method.
i.e.
public class Discount {
//Use a hash map to store your Code associate with your discountAmount
public Discount(char discountCode){
this.discountCode = discountCode
}
public int getDiscountAmount(){
....
....
}
}
Right now, what you actually need to modify will be the Discount Class only, and your calculateTotalPriceWithDiscountCode will not need to care.

You could use a separate xml file for storing codes as well as their calculation mechanishms.
This will remove the limitation of inablility to add new discount code.
XML File: discounts.xml
<discount-codes>
<discount-code>
<code>A</code>
<val>0.15</val>
</discount-code>
<discount-code>
<code>B</code>
<val>0.95</val>
</discount-code>
</discount-codes>
Note: Operation code (What am I intended to do with the values?) is not currently implemented. You can implement the same at your end.
Use an XML parser class:
Class: DiscountModel.java (This class is the model to store the discount codes)
public class DiscountModel {
char code;
Double val;
// Implement getters and setters
}
Class: DiscountParser.java (This will parse the discounts.xml file and store the codes in a list)
public class DiscountParser {
List<DiscountModel> discountsList;
// Getters and Setters for discountsList
// Parser Code
public void parseDiscounts() {
// Code here
}
// Add new discount
public void addDiscount() {
// Code
}
// Remove discount
public void removeDiscount () {
// Code
}
}
Class: OrderProcessor.java (This will bring out the discounted value after calculation)
/**
* Call this class when calculations need to be done.
*/
public class OrderProcessor {
// Declare instance of DocumentParser
DocumentParser dc1;
// Getter and setter for dc1
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
// Find the corresponding discountcode and
// value from the list of values in the
// Class DocumentParser
// Use the corresponding values to calculate
// the discount and return the value
}
}
Whenever a new code is to be added, you can insert the same to the xml file. The same applies if the discount code needs to be removed.
Hope the above helps.

Related

Java method taking 0 arguments and returning a double using if else statements with strings

I am trying to write a method which does not take any arguments and then returns a double variable. It is a postcode identifier so when a cost code is entered certain post codes need to return a double.
In my example below i need post codes that start with either "GH6 TXX" or "NC4 LXX". (X stands for any random character or digit) to return 50.0.
If any other postcode is entered then return 100.0.
However i am not getting any results back and just finding errors. I'm sure i have gone massive wrong somewhere as im not great with If Else statements within methods. Any help or knowledge on this would be great!
public class multiPostcodeRange {
//Declaring Variables
String pcode;
public multiPostcodeRange()
{
pcode = "XXX XXX";
}
public void multiPostcodeRange()
{
if (pcode("GH6 TXX", "NC4 LXX")) {
return 100.0; }
else {
return 50.0;}
} }
public class MultiPostcodeRange {
private String pcode;
public MultiPostcodeRange() {
pcode = "XXX XXX";
}
public double multiPostcodeRange() {
if (pcode.equals("GH6 TXX") || pcode.equals("NC4 LXX")) {
return 100.0;
}
else {
return 50.0;
}
}
}
To return double from a function you need to define a return type for the function.
public double multiPostcodeRange
You created a class with his methods (which btw you shouldn't name as the class, but give them unique names).
Then you have to create a new instance object of that class and call the method on a main function.
For example, at the end of your code:
`public static void main(String args[]){
multiPostcodeRange Obj = new
multiPostcodeRange();
Obj.meth1();
Obj.meth2();}`
NB remember to give those methods unique names!
Also change 2nd method body and type as AndyMan's answer

ArrayList<Object> how to differentiate objects added

the question is the same as in the title. i have arraylist to which i add incomes or expenses both in form of a object. will this loop sum up all elements, and is there a better way of doing this :?
public void sumOfAllExpAndIn(){
int tmp = 0;
for (Iterator<Object> it = database.iterator(); it.hasNext();){
if (it.next() instanceof Expenses){
Expenses excalc = new Expenses();
excalc = (Expenses) it.next();
tmp -= excalc.value;
}
else {
incomes incalc =new incomes();
incalc = (incomes) it.next();
tmp += incalc.value;
}
}
System.out.format("the overall balance is %d",tmp);
}
Yes there are several better ways of doing it.
Firstly, I don't suggest you declare it as an Object list. Better is to declare an interface and then implement the interface in each of your classes:
interface BudgetValue {
double getValue();
}
class Expense implements BudgetValue {
public double getValue() {
return -value;
}
}
class Income implements BudgetValue {
public double getValue() {
return +value;
}
}
Then you can declare list of BudgetValues rather than Objects as the input to your method:
double sumBudgetValues(List<BudgetValues> budgetValues) {
}
There are two easy ways of summing them:
double total = 0.0;
for (BudgetValue value: budgetValues) {
total += value.getValue();
}
return total;
or using Java 8:
return budgetValues.stream()
.mapToDouble(BudgetValue::getValue)
.sum().orElse(0.0);
The streams method makes a lot more sense to me and allows it to be easily multithreaded if you have a lot of values to sum by turning it into a parallel stream.
There are some rare occassions where instanceof is justified but, as a rule of thumb, if you find yourself using it then start by asking yourself whether there's an interface missing.
I suggest making your Expenses and Incomes classes implement a common interface, for example LineItem. Now if you use signed values (positive for incomes and negatives for expenses), you only have to call getValue() on any implementation of LineItem and add it to your running total... no if/else needed, no collection of Object needed.
public void sumOfAllExpAndIn(){
int tmp = 0;
for (Iterator<LineItem> it = database.iterator(); it.hasNext();){
tmp += it.next().getValue();
}
}
System.out.format("the overall balance is %d",tmp);
}

How to change code that uses many if statements to choose a class by name?

I'm working on a program to simulate an RLC circuit. The program makes some specific calculations based on the type of circuit and type of source (RLC, LC, RC ,sinusoidal, DC, square ...) which later are added to Charts.
The following code works the way I need it to, but my teacher told me that it will be better if I make an individual class for every case, because too many if statements are not good.
if(scheme == "RLC"){
beta = R / (2*L);
omega0Square = 1/ (L*C);
//Resonant
if (omega * omega == omega0Square
&& beta >= Math.sqrt(omega0Square) / Math.sqrt(2)){
chargeAmp = U0 / (L*2*beta*Math.sqrt(omega0Square - beta*beta));
fi = Math.atan(Math.sqrt(omega0Square-2*beta*beta)/beta);
}
//Non-resonant
else{
omegasDifference = (omega0Square - omega * omega);
fi = Math.atan(2 * beta * omega / omegasDifference);
chargeAmp = U0/(L*Math.sqrt(omegasDifference * omegasDifference
+ 4 * beta * beta * omega * omega));
}
intensity = chargeAmp*omega* Math.cos(omega*time-fi);
rU = R * intensity;
cQ = chargeAmp*Math.sin(omega*time-fi);
lE = L*intensity*intensity/2;
}
if(scheme == "LC"){
}
if(scheme == "RC"){
}
if(scheme == "R"){
}
if(scheme == "L"){
}
if(scheme == "C"){
}
if(scheme == "Non"){
}
If I made a class for every case, how can i manage them later, and invoke them without using if statements? I thought about something like this:
String name;
name variable = new name();
Is it possible? Or is there a better way?
Use Interfaces and factory pattern
Create a class to hold the values ( R,L,C)
public class RLCHolder {
double rValue;
double lValue;
double cValue;
//Setter and Getters
}
Create an Interface
public interface CircuitCalculator {
public double calculate(RLCHolder rlcHolder);
}
Now implement the Interface
public class RLCCircuitCalculator implements CircuitCalculator {
#Override
public double calculate(RLCHolder rlcHolder) {
// Do you Math and Return
return 0;
}
}
Like this add your implementation for other Circuits like.
LCCircuitCalculator , RCCircuitCalculator and so
Now create Factory method and call the calculate method
public class Calculator {
// factory method
public static CircuitCalculator getCircuitCalculator(String circuitName){
CircuitCalculator circuitCalculator = null;
if (circuitName.equals("RLC")){
circuitCalculator = new RLCCircuitCalculator(); // You can cache if you dont maintain state
}else if (circuitName.equals("LC")){
// return LC object
}//add your implementation..
return circuitCalculator;
}
public static void main(String args[]){
RLCHolder rlcHolder = new RLCHolder();
double result = Calculator.getCircuitCalculator("RLC").calculate(rlcHolder);
}
}
Since you have different circuit i don't think you can really escape from using if statement or more elegant way you can use switch. What your teacher mean by creating seperate class for each circuit its because he want you have small chunk of code inside your if statement if you start coding like the way you code right now it will be a huge function.

a question on conversion logic

I am designing a unit converter using android.i m using logic which is not nice logic i think and i m giving some code here too.can anyone suggest me any better logic????
public void temperature(String value1,String value2)
{
if(value1.equals("Celsius") && value2.equals("fahrenheit") )
{
double i=Double.parseDouble(at1.getText().toString());
double value=i*33.8;
Double d=new Double(value);
at2.setText(d.toString());
}
else if(value1.equals("fahrenheit") && value2.equals("Celsius"))
{
double i=Double.parseDouble(at1.getText().toString());
double value=i*(-17.2222);
Double d=new Double(value);
at2.setText(d.toString());
}
There is like this many unit in every category like angle,computer.this is only a small example of temperature category.
Why not just
at2.setText(String.valueOf(Double.parseDouble(at1.getText().toString()) * 33.8);
Anyway, it's just to shorten your code, the logic stays the same.
P.S. Define some constants for values like 33.8 and -17.2222.
There's a lot of duplicated code in your example. Try to refactor it so you common actions are expressed only once.
Example:
public void temperature(String value1, String value2) {
double i = Double.parseDouble(at1.getText().toString());
double value;
if (value1.equals("fahrenheit") && value2.equals("celsius")) {
value = /* convert i */;
} else if (....) {
value = ...;
}
at2.setText(String.valueOf(value));
}
If your list of if statements becomes large, consider using a switch statement instead. You might want to change representation of the units from String to something else like integer constants or enums.
My suggestion would be to use the command pattern.
For temperature, I believe you can use Kelvin to convert to a common scale:
public class TemperatureConverter {
private final static String CELSIUS = "Celsius";
private final static String FARENHEIT = "Farenheit";
public double temperature(double temperature, String temp1Type, String temp2Type) {
Converter fromConverter, toConverter;
if (temp1Type.equals(CELSIUS)) {
fromConverter = new CelsiusConverter();
} else if (temp1Type.equals(FARENHEIT)) {
fromConverter = new FarenheitConverter();
} else {
fromConverter = new noopConverter();
}
if (temp2Type.equals(CELSIUS)) {
toConverter = new CelsiusConverter();
} else if (temp2Type.equals(FARENHEIT)) {
toConverter = new FarenheitConverter();
} else {
toConverter = new noopConverter();
}
return toConverter.fromKelvin(fromConverter.toKelvin(temperature));
}
}
Converter is an interface, and FarenheitConverter and CelsiusConverter are concrete classes that implement this interface. They contain the details to convert from Farenheit and Celsius (respectively) to Kelvin. They also contain the details of converting from Kelvin to their respective scales. This keeps the logic cleanly separated, and easily extended in the future.
Say in the future you need to convert from degrees blignox to degrees fizzbuzz. It's as simple as writing the BlignoxConverter and the FizzbuzzConverter, implementing the two methods, and plugging them in. Once they're written and integrated, you can convert from either of those to or from F and C as well.

Help with method logic in Java, hw

I have a Loan class that in its printPayment method, it prints the amortization table of a loan for a hw assignment. We are also to implement a print first payment method, and a print last payment method. Since my calculation is done in the printPayment method, I didn't know how I could get the value in the first or last iteration of the loop and print that amount out.
One way I can think of is to write a new method that might return that value, but I wasn't sure if there was a better way. Here is my code:
public abstract class Loan
{
public void setClient(Person client)
{
this.client = client;
}
public Person getClient()
{
return client;
}
public void setLoanId()
{
loanId = nextId;
nextId++;
}
public int getLoanId()
{
return loanId;
}
public void setInterestRate(double interestRate)
{
this.interestRate = interestRate;
}
public double getInterestRate()
{
return interestRate;
}
public void setLoanLength(int loanLength)
{
this.loanLength = loanLength;
}
public int getLoanLength()
{
return loanLength;
}
public void setLoanAmount(double loanAmount)
{
this.loanAmount = loanAmount;
}
public double getLoanAmount()
{
return loanAmount;
}
public void printPayments()
{
double monthlyInterest;
double monthlyPrincipalPaid;
double newPrincipal;
int paymentNumber = 1;
double monthlyInterestRate = interestRate / 1200;
double monthlyPayment = loanAmount * (monthlyInterestRate) /
(1 - Math.pow((1 + monthlyInterestRate),( -1 * loanLength)));
System.out.println("Payment Number | Interest | Principal | Loan Balance");
// amortization table
while (loanAmount >= 0) {
monthlyInterest = loanAmount * monthlyInterestRate;
monthlyPrincipalPaid = monthlyPayment - monthlyInterest;
newPrincipal = loanAmount - monthlyPrincipalPaid;
loanAmount = newPrincipal;
System.out.printf("%d, %.2f, %.2f, %.2f", paymentNumber++, monthlyInterest, monthlyPrincipalPaid, loanAmount);
}
}
/*
//method to print first payment
public double getFirstPayment()
{
}
method to print last payment
public double getLastPayment()
{
}*/
private Person client;
private int loanId;
private double interestRate;
private int loanLength;
private double loanAmount;
private static int nextId = 1;
}
Thanks!
You've already identified that the printPayments(), printFirstPayment() and printLastPayment() methods have common logic. You generally want to minimize duplication of such code and the two common ways to do this are:
Implement all but one of the methods in terms of one of them; or
Implement all the methods in terms of a private method.
So, for example:
public void printPayments() {
for (Payment : getPayments()) {
printPayment(payment);
}
}
public void printFirstPayment() {
printPayment(getPayments().get(0));
}
public void printLastPayment() {
List<Payment> payments = getPayments();
printPayment(payments.get(payments.size()-1));
}
private void printPayment(Payment payment) {
...
}
private List<Payment> getPayments() {
...
}
Now this is homework so you may not have come across the syntax List<Payment> yet. If not, it's generics. There are other ways to do this: using a non-generic Collection or using arrays for example.
The points I wanted to illustrate here is that:
The logic for creating the payments and displaying them has been separated;
A single method getPayments() does the calculations and returns a List of Payment objects. Payment is a new object in this mock up;
All three methods are implemented in terms of getPayments() and printPayment().
So I hope this leads you in the right direction. The concept here I guess is functional composition, composing your functions in terms of other functions and making your internal functions granular enough to be grouped together usefully.
Your printPayments function is awfully big. It is generally better to make each function "do one thing and one thing well", and to make functions relatively short. I would recommend that you separate your computation logic from your printing logic; provide functions for computing these various payments, and have your print function merely print the result of invoking those computation functions.
If you are worried about redundancy (that is some of the later computations depend on earlier computations which you might have previously performed), then you can use dynamic programming, which basically means that you accumulate previous results in an array or matrix so that they can be reused in subsequent computations. You could compute the entire amortization table as a 2-dimensional array, in which case you could lookup the earlier payments that you computed simply by looking them up in that array.
Maybe you should have a method that returns an array/set/list/resultset/datacontainer (add more buzzwords to confuse you - its your homework after all ;)) which you can use in the other methods.
if when you describe what a method does, you use the word 'and', chances are the method is doing too much. each method should do one thing, so printing is one thing, and calculating is another .. so two methods.

Categories

Resources