Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
My computer science teachers have told me that I should not be printing strings from methods such as getters and that I should be printing from the main method to the user. I was wondering if it mattered where I print from and what is the proper way to structure my code.
For example:
public class Main {
public static void main(String[] args) throws IOException {
Bank bank = new Bank(20);
System.out.println(bank.getBalance());
}
}
public class Bank {
int balance;
public Bank(int balance){
this.balance = balance;
}
public String getBalance(){
return "You have $" + this.balance;
}
}
as opposed to how my teacher says I should write it
public class Main {
public static void main(String[] args) throws IOException {
Bank bank = new Bank(20);
System.out.println("You have $" + bank.getBalance());
}
}
public class Bank{
int balance;
public Bank(int balance){
this.balance = balance;
}
public int getBalance(){
return this.balance;
}
}
Your teacher is right.
You are not really printing anything in your getters, just that you are obscuring the data types. A balance of an account (not really a bank) is presumably a numeric type (int, long) and not a String.
In general, let your methods do one thing right. By printing something in your getter and returning is okay for debugging, but not advisable in general. And that's what your teacher means.
Writing classes that have well-defined and type-safe API is useful and important especially in Java.
Your teacher is correct.
The purpose of the getBalance method is to "get" the balance in a way that other parts of your application can use it. There are lots of ways that the balance could be used, including printing it (in various places / various ways) adding it to a spreadsheet, adding it to a total, etcetera.
If you design your getBalance() method to just format and print the balance (to standard output), then all of the other things require other methods ... for each other thing.
There is a principle in software engineering known as "separation of concerns". A class (or more generally, a module) should do the things that it needs to do, and leave the other things to the caller of the classes methods. In this case, we are talking about SoC at a fine-grained level ... but the principle applies at this level too.
The version your teacher would have you write makes more sense to me. As a user of your Java classes, I prefer getting the balance as a numeric and then use it any way I wish. Presenting the data as a USD string is obviously a valid use case, but not the only one I could think of. Suppose, as a client of your class, that I'd like to know how many euros, pounds or rupees I could get with my account, then the second implementation would suit me better.
Your teacher is probably suggesting that the Bank should not be responsible for how to display the balance as a string, since different people using the bank may want to display the balance differently.
One way to deal with this is by simply keeping the bank as your professor suggests, and just format it in your own way after you get the balance number.
Second way is to make your own formatter class that formats the string in the way you want like:
public class Main2
{
public Main2() {
Bank bank = new Bank(20);
System.out.println(BalanceFormat.formatBalance(bank.getBalance()));
}
public static void main(String[] args) {
new Main2();
}
}
class Bank {
private int balance;
public Bank(int balance) {
this.balance = balance;
}
public int getBalance() {
return balance;
}
}
class BalanceFormat
{
public static String formatBalance(int balance) {
return ("Your balance is $" + balance);
}
}
The third way to do this is via callbacks, this way you tell the bank how you want it to behave while it maintains its' defaults.
public class Main
{
public Main()
{
Bank bank = new Bank(20);
System.out.println(bank.getBalanceString());
Bank bank2 = new Bank(20, (balance) -> {
return ("Your balance is: $" + balance);
});
System.out.println(bank2.getBalanceString());
}
public static void main(String[] args)
{
new Main();
}
private class Bank
{
int balance;
BalanceStringCallback bankPrintBehavior = null;
public Bank(int balance, BalanceStringCallback callback)
{
this.bankPrintBehavior = callback;
this.balance = balance;
}
public Bank(int balance)
{
this.balance = balance;
}
public int getBalance()
{
return this.balance;
}
public String getBalanceString()
{
if (bankPrintBehavior == null) {
return String.valueOf(balance);
} else {
return (bankPrintBehavior.callback(balance));
}
}
}
#FunctionalInterface
private interface BalanceStringCallback
{
abstract String callback(int balance);
}
}
There are other ways, like creating your own subclass of Bank and make it know how to format in the way you like it(Although this makes changing how one bank behaves harder, whereas the third approach of callbacks also allows you to change the behavior on the fly), but those three ways are first that popped to mind.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 17 hours ago.
This post was edited and submitted for review 16 hours ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
Here is the problem:
Create a class named BankAccount, containing:
a constructor accepting a String corresponding to the name of the account holder.
a method, getBalance, that returns a double corresponding to the account balance.
a method withdraw that accepts a double, and deducts the amount from the account balance.
Write a class definition for a subclass, CheckingAccount, that contains:
a boolean instance variable, overdraft. (Having overdraft for a checking account allows one to write checks larger than the current balance).
a constructor that accepts a String and a boolean. The String parameter is used in the invocation of the superclass (BankAccount) constructor, while the boolean is used to initialize the overdraft instance variable.
a method, hasOverdraft, that returns a boolean. hasOverdraft returns true if the account supports overdraft.
a method, clearCheck, that accepts a double and returns a boolean. clearCheck will determine if the amount (of the check) can be cashed-- this will be the case if the amount is less than the balance in the account, or if the account allows overdraft. If the check can be cashed, clearCheck returns true, and also calls the withdraw method to update the account balance; otherwise, clearCheck returns false.
In the main method, create an object of type CheckingAccount, accepts input from the user to fill the information, and call all the methods of this object.
Currently, I have both the BankAccount and CheckingAccount done which leaves the main body to do. Unfortunately, I have no idea about how to do the Main Method/body for this assignment. Besides only a brief excerpt above, which will be bolded, I have no idea.
Below is what I have so far.
import java.util.Scanner;
//Main Class
public class S2W5PA {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
System.out.println("Enter Name of Account: ");
String name=input.nextLine();
CheckingAccount CA=new CheckingAccount(name, check);
}
}
//BankAccount Class
public class BankAccount {
private String name;
private double balance;
BankAccount(String name){
this.name=name;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
public void withdraw(double amount){
this.balance-=amount;
}
public void deposit(double amount){
this.balance+=amount;
}
}
//CheckingAccount Class
public class CheckingAccount extends BankAccount {
public CheckingAccount(String name, boolean overdraft) {
super(name);
this.overdraft = overdraft;
}
public boolean hasOverdraft() {
return overdraft;
}
public boolean clearCheck(double amount) {
if (getBalance() >= amount || overdraft)
{
withdraw(amount);
return true;
}
return false;
}
private boolean overdraft;
}
I am trying to make sure I'm doing it correctly and not missing any details. I think most of the work is done but I feel like I am missing something.
I am confused about state pattern implementation. Under this pattern, we should extract state management into separate classes. At first glance it allows us to avoid big if ... else ... constructions inside domain entity and it really powerful advantage. We can move all condition checks into state classes and clear our domain entity class.
But how to modify the data encapsulated in the domain object without encapsulation principle violation?
For example, consider the Account entity. In a simplified way, it has two possible states - Active and Blocked and methods for money deposit and withdrawal.
Under the state pattern, we should delegate deposit and withdrawal responsibilities to state classes. UML diagram here.
But how can we modify the money and state fields from AccountState implementations? I see only the way where I have public setters for it. But it violates the encapsulation principle. With this approach, I can also change private fields to the public.
Code example:
class Account {
private int money;
private AccountState state;
public Account() {
this.money = 0;
this.state = new Active();
}
public void deposit(int amount) {
this.state.deposit(this, amount);
}
public void withdraw(int amount) {
this.state.withdraw(this, amount);
}
public int getMoney() {
return this.money;
}
public AccountState getState() {
return this.state;
}
}
interface AccountState {
public void deposit(Account account, int amount);
public void withdraw(Account account, int amount);
}
class Active implements AccountState {
public void deposit(Account account, int amount) {
// How to change account money and state without setters and public fields usage?
}
public void withdraw(Account account, int amount) {
if (account.getState() instanceof Blocked) {
throw new RuntimeException("Money could not be withdrawn. Account is blocked.");
}
if (account.getMoney() - amount <= 0) {
throw new RuntimeException("Money could not be withdrawn. Insufficient funds.");
}
// How to change account money and state without setters and public fields usage?
}
}
class Blocked implements AccountState {
public void deposit(Account account, int amount) {
// How to change account money and state without setters and public fields usage?
}
public void withdraw(Account account, int amount) {
if (account.getMoney() - amount <= 0) {
throw new RuntimeException("Money could not be withdrawn. Insufficient funds.");
}
// How to change account money and state without setters and public fields usage?
}
}
This is a very simplified example, but it well reflected my problem. Unfortunately, I couldn't found a good solution for it. All examples that I saw use either public setters or public fields. Also, I saw an example from the Refactoring to Patterns book by Joshua Kerievsky. He offers to use setters with package-level access (without access modifiers like private, public, or protected). So, we can change entity data from state classes located in the same package with the domain entity and can not do it from other packages. But this approach is using the language-specific feature - package-level access. In other languages like PHP, it wouldn't work. I'm looking for a conceptual solution.
Can anyone show a real production example solving this problem? I would really appreciate it.
Public setters (or actually setters in general regardless of access modifier) do not violate encapsulation. Encapsulation means we set up the class so only methods in the class with the variables can refer to the instance variables. In correctly encapsulated classes, callers are thus required to use these methods if they want to modify class fields.
To allow calls only from specific classes you could use reflection.
Example in Java:
How to get the caller class in Java
Example in PHP:
https://stackoverflow.com/a/6927569/724099
I would either:
Move money into AccountState (as the AccountState largely operates with money in this example)
Provide a method which manipulates Account in a way you prescribe. This may be through a method like Account#transact(String label, double amount), allowing you to manipulate the balance without exposing the member.
Remove AccountState as a redundant class, since the fields of a class are to represent the state of an object.
The second can be done through the function API as well, but do not confuse the mutability of a class member with breaking encapsulation; the purpose of encapsulation is to disallow unwanted behavior (like arbitrary math or access to internal collections). This prevents the class from entering an erroneous state.
There are many ways to solve this problem, depending on exactly what you need each state instance to do. In this specific example, I would pass the field value of money into the AccountState rather than the entire Account object.
Here is an example using an enum, but obviously that could be two separate classes with an interface instead.
public class Account {
private int balance = 0;
private AccountState currentState = AccountState.ACTIVE;
public int deposit(int amount) {
balance = currentState.deposit(balance, amount);
return balance;
}
public int withdraw(int amount) {
balance = currentState.withdraw(balance, amount);
return balance;
}
public AccountState activate() {
this.currentState = AccountState.ACTIVE;
return currentState;
}
public AccountState block() {
this.currentState = AccountState.BLOCKED;
return currentState;
}
enum AccountState {
ACTIVE {
#Override int deposit(int balance, int amount) {
return balance + amount;
}
#Override int withdraw(int balance, int amount) {
int newBalance = balance - amount;
if (newBalance >= 0) {
return newBalance;
}
throw new IllegalArgumentException("Withdrawal amount is greater than balance.");
}
},
BLOCKED {
#Override int deposit(int balance, int amount) {
throw new UnsupportedOperationException("Account is blocked.");
}
#Override int withdraw(int balance, int amount) {
throw new UnsupportedOperationException("Account is blocked.");
}
};
abstract int deposit(int balance, int amount);
abstract int withdraw(int balance, int amount);
}
}
One clue that the code in the OP will be difficult to apply OOP patterns to is that the business logic methods (deposit and withdraw) return void. It's difficult to do anything other than procedural programming with void methods. Make your methods return appropriate values and you will have an easier time composing classes that interact naturally.
Let's say in a simple shopping application there are a Customer class, Seller class, and Trade class, and the code looks simply like this(to illustrate my question):
public class HelloWord {
public static void main(String[] args) {
Customer customer = new Customer();
Seller seller = new Seller();
Trade trade = new Trade(customer,seller);
trade.buy(2);
}
}
class Customer {
private ArrayList<String> itemCart = new ArrayList<String>();
private int gold = 100;
public void setGold(int amount) {
if (gold - amount >= 0) {
gold -= amount;
}
}
public int getGold() {
return gold;
}
public void add(String item) {
itemCart.add(item);
}
}
class Seller {
private ArrayList<String> itemCart = new ArrayList<String>();
private ArrayList<Integer> itemsPrice = new ArrayList<Integer>();
public int getItemPrice(int itemID) {
return itemsPrice.get(itemID);
}
public String getItemById(int itemID) {
return itemCart.get(itemID);
}
}
class Trade {
private Customer customer;
private Seller seller;
public Trade(Customer customer, Seller seller) {
this.customer = customer;
this.seller = seller;
}
public void buy(int itemID) {
if (seller.getItemPrice(itemID) <= customer.getGold()) {
customer.add(seller.getItemById(itemID));
customer.setGold(seller.getItemPrice(itemID));
} else {
System.out.println("You don't have enough money to buy this item");
}
}
}
My question is "Do the "setGold" and "add" methods expose the attruputs?" i don't want the user to be able to modify the itemCart neither the gold attribute by just call the add method or setGold on his own, but i want to be able to access them to modify the attruputs using other methods, in this case from "buy" method in Trade class.
My question in other words: "Should i be concerned if these method could be accessed from the main method or that is normal and does not violate data integrity?"
You are not getting the answer you expect because the question is a bit confusing as it is now. Reading through it carefully, you are not asking if the main method can access/change the Customer properties directly, but if the main method can use the add and setGold methods to change those properties. Also, the Seller class is just adding entropy as it's not relevant for the question.
Breaking it down:
Do the "setGold" and "add" methods expose the attruputs?
The attributes themselves are not exposed but both methods allow modifying those attributes from the outside since they are declared as public.
i don't want the user to be able to modify the itemCart neither the gold attribute buy just call the add method or set gold on his own
This is possible with your current code as both add and setGold are public. That's exactly the purpose of public.
but i want to be able to access them to modify them using other methods, in this case from "buy" method in Trade class
If you want add and setGold to be visible only to the Trade class, one option is to put Trade and Customer classes in the same package as in the following example:
com.example
shopping
|--- Customer.java
|--- Trade.java
application
|--- HelloWorld.java
And then make both methods package-private, like so:
public Customer {
// ... properties and other methods
void setGold(int amount) {
if (gold - amount >= 0) {
gold -= amount;
}
}
void add(String item) {
itemCart.add(item);
}
}
The difference to your code is that neither method contains a visibility modifier (removed the public keyword), making them package-private, thus only accessible from the same package.
With that structure and package-private methods in the Customer class, if you call the add or setGold from the main class you will get a compiler error:
add(java.lang.String) is not public in com.example.shopping.Customer;
cannot be accessed from outside package
But you can still access it from the Trade class because it's in the same package.
Short ans no, since itemCart is private, runtime caller can't access that directly.
Long answer https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html.
The purpose of data encapsulation is to hide the implementation of an object by ensuring that the contents of the object are only modifiable through the interface of the object. By that definition - the Trade object inherently breaks encapsulation because of its constructor. Since you are passing in references to Customer and Seller, any invariants that the Trade object is supposed to maintain can be broken simply by the person modifying the customer or seller directly.
It's hard to know what the best alternative is without more context, but a possible fix could be rather than passing in the Customer and Seller on construction of the Trade object, passing them into the buy function. Another solution could be to attach the buy function to the Customer or Seller objects instead, getting rid of the Trade object altogether. Generally classes in OOP represent objects, and not actions (outside of certain design patterns).
The setter itself doesn't expose anything. So long as you're not exposing the exact fields (e.g. you're not doing getItemsPrice and returning an ArrayList), you're fine.
All bets are off with reflection, however. But, that's not the concern here.
I suggest you should change the setter to common form, and you can make it private.
private void set(int amount) {
this.amount = amount;
}
public boolean spend(int amount) {
if (gold - amount >= 0) {
gold -= amount;
return true;
} else {
return false;
}
}
In buy method, invoke spend().
I am new to Spring and while learning the concepts I noticed that all the members are kept private i.e private access modifier is used.
eg.
private String car;
Is there any special reason for this?
The idea behind private members is that the class itself retains the responsibility of its internal state, instead of the calling class. Consider a banking account class. You wouldn't want a calling class to be able to access its amount directly. Instead, you would provide other methods which contain logic, based on what the calling class wants.
private int amount;
public int getAmount() {
return amount;
}
public void withdraw(int amount) {
if (this.amount - amount >= 0) {
this.amount -= amount;
}
}
public void deposit(int amount) {
this.amount += amount;
}
The above class would allow a calling class to make deposits, withdrawals and inspect the amount, while the class itself would retain responsibility over its state.
I've been trying to figure out if theres a way to pass a string to a factory or constructor and create the correct object without having to map the string to an object, or without having a bunch of if/else statements or switch statements.
Keep in mind, this is a simple example so I can apply what I learn to more complicated situations in web apps, etc.
let's take a simple calculator app, written in JAVA, as an example
assuming this is command line, and a person can pass in 3 values
- first number
- math operation (+ , - , / , x)
- second number
and we have an interface
public interface ArithmeticOperation {
public double performMathOperation(double firstNum, double secondNum);
}
with 4 classes that implement it
public class AdditionOperation implements ArithmeticOperation {
public double performMathOperation(double firstNum, double secondNum) {
return firstNum + secondNum;
}
}
// public class Subtraction operation returns firstNum - secondNum
// etc...
and we have our actual Calculator class and UserInput class
public class UserInput {
public UserInput(double firstNum, double secondNum, String operation) {
this.firstNum = firstNum;
// etc...
}
}
public class Calculator {
public UserInput getInput() {
// get user input, and return it as a UserInput object
// return a UserInput object
}
public performOperation() {
UserInput uInput = getInput();
double answer = ArithmeticOperationFactory
.getSpecificOperation(uInput.operation)
.performMathOperation(uInput.firstNum, uInput.secondNum);
// send answer back to user
}
}
finally, the place where the question mostly revolves around, the factory
public class ArithmeticOperationFactory {
public static ArithmeticOperation getSpecificOperation(String operation) {
// what possibilities are here?
// I don't want a map that maps strings to objects
// I don't want if/else or switch statements
// is there another way?
}
}
also, if theres a better way to architect a system like this or a design pattern that can be applied, please share. I'm really trying to learn some good object oriented design
There is a different way. I'm not sure it's better.
We have to go back to the interface and add another method so that the class can identify the operator.
public interface ArithmeticOperation {
public boolean isOperator(String operator);
public double performMathOperation(double firstNum, double secondNum);
}
We code the concrete methods like this:
public class AdditionOperation implements ArithmeticOperation {
#Override
public boolean isOperator(String operator) {
return operator.equals("add");
}
#Override
public double performMathOperation(double firstNum, double secondNum) {
return firstNum + secondNum;
}
}
We put all of the ArithmeticOperation classes in a List
List<ArithmeticOperation> operations = new ArrayList<>();
operations.add(new AdditionOperation());
...
Finally, we perform the operation like this.
double answer = 0D;
for (ArithmeticOperation operation : operations) {
if (operation.isOperator(currentOperator) {
answer = operation.performMathOperation(firstNum, secondNum);
break;
}
}
I would implement it using switch case. This is Factory Design Pattern.
class ArithmeticOperationFactory {
public static ArithmeticOperation getSpecificOperation(String operation) {
switch (operation) {
case "ADD":
return new AdditionOperation();
case "SUBTRACT":
return new SubtractOperation();
// You can define the rest of the operation here.
default:
throw new UnsupportedOperationException("OPeratino is not supported: " + operation);
}
}
}
You can also define Enum for each operation and use them in switch-case.
There is no method which is much better than solutions you have seen before. You can only make it slightly more elegant. In essence you can have:
Bunch of if/else/switch (probably least elegant but fast)
if("typeAsString").equals("operation"){
return new SomeType()
}
Map
Map<String, Class<? extends YourType> map = new HashMap<>();
You can make it bit better with dependency injection or you can make each subclass to add its own entry in this map. I'd favor keeping configuration away from factory class and moving it to subclasses.
Kind of chain of responsibility
You have to create Collection of all your subtypes. Each subtype has to have method like isItCorrectSubtype(). Client class has to iterate through whole collection and check which implementation is correct
#Autowired
List<InterfaceOfYourTypes> allSubtypes;
..
public void doStuff(){
for(InterfaceOfYourTypes subtype: allSubtypes){
if(subtype.isCorrectSubtype()){
//create instance
}
}
}
What are you asking for is a mapping operation because you have a String as input and you want an Object implementing and interface (ArithmeticOperation) back. If a mpa dose not fit you needs you must "configure" the mapping in a different way, this is my suggestion:
Change the interface to
public interface ArithmeticOperation {
public double performMathOperation(double firstNum, double secondNum);
public double getName();
}
Your add operation will result as the following one:
public class AdditionOperation implements ArithmeticOperation {
public double performMathOperation(double firstNum, double secondNum) {
return firstNum + secondNum;
}
public double getName() {
return "+";
}
}
In you method factory all you need is to find all the classes implementing the ArithmeticOperation interface; something like:
public class ArithmeticOperationFactory {
private List<ArithmeticOperation> availableOperations=null;
//to be called at application startup
public static void findAvailableOperations() {
// a strategy for finding implementations that fills
// availableOperations
}
public static ArithmeticOperation getSpecificOperation(String operation) {
for (ArithmeticOperation arithmeticOperation : availableOperations) {
if (operation.equalsIngoreCase(arithmeticOperation.getName)) {
return arithmeticOperation;
}
}
}
Here are some method you can yous to implement findAvailableOperations:
If you are using Spring you can get the api getBeansOfType and retrieve all the implementations (I'm assuming you are configuring the concrete operations as Spring beans).
If you are not using spring you can scan the classpath in order to find the classes that implement your interface; you can start from this project or this one.
Another solution is to put the implementation class names into a file (.properties, .xml, .json, etc), read the class names and create them via reflection.
You could use a Factory like this
public class ArithmeticOperationFactory {
public static ArithmeticOperation getSpecificOperation(String operation) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
return (ArithmeticOperation) resolveClass(operation).newInstance();
}
private static Class resolveClass(String className) throws ClassNotFoundException {
return Class.forName(className);
}
}