One argument that is often made concerning avoiding switch statements is that if there is a change/addition, you will have to look all over your code where in your code switch statements are that are effected by a new choice. (and you might forget to change one).
That sounds interesting, but if I use other constructs like function pointers (jump tables) like here:
[https://ultimatecourses.com/blog/deprecating-the-switch-statement-for-object-literals][1]
or here
[https://simpleprogrammer.com/refactoring-switches-to-classes/][1]
I will have the same problem in adapting those when new choices are required.
So.. if I have switches/choices at all, what is the best choice to implement the "Open/Closed principle"?
The only way I see is instead of using
switch(person.position){
case "manager":
break;
case "worker":
break;
case: "temp"
....
is to feed the whole Person object for "John Smith" into a function where then the appropriate functions will be invoked.
The switch statement will be in the class:
class Person {
...
...
public void applyBonus(){
switch (this.position) {
case "manager": this.addBonus(10000)
break;
}
}
If now any changes are requested it's only in the "Person" class.
Do I get this right?
I answered a similar question earlier today (but in C#). Your Person could be abstract and force classes that implement the Person class to define it's bonus amount. Then your base class could simply implement a applyBonus. For example:
public abstract class Person
{
protected double salary, bonusAmount, baseSalary;
protected Person(double baseSalary, double bonusAmount)
{
this.baseSalary = baseSalary;
this.bonusAmount = bonusAmount;
}
public void applyBonus()
{
salary += bonusAmount;
}
}
public final class Manager extends Person {
public Manager()
{
super(100000.0, 1000.0);
}
}
public final class Worker extends Person {
public Worker()
{
super(10000.0, 500.0);
}
}
public final class TempWorker extends Person {
public TempWorker()
{
super(1000.0, 200.0);
}
}
Now you can do things like:
var myTeam = new Person[] { new Manager(), new Worker(), new Worker(), new TempWorker() };
// apply bonuses:
for(var member : myTeam){
member.applyBonus();
}
Now, I'm not saying this is how you should do this, by any means. I am showing you how polymorphism and other OOP patterns can help you think more abstractly about the objects in your program and avoid iterating through types.
Related
Yesterday, I had an interview and I was given the following scenario:
There are 3 classes namely Main.java, MobilePhone.java, DeskPhone.java and one Interface ITelephone.java. powerOn() method is implemented in both classes MobilePhone.java and DeskPhone.java.
How can I call powerOn() method in DeskPhone class after creating an instance of MobilePhone class? In other word, how can I print "You are in DeskPhone class" and "You are in MobilePhone class" in last two calls in Main class?
Is there any another way to solve this problem without renaming powerOn() method in either of class?
Main.java
public class Main {
public static void main(String[] args) {
ITelephone timsPhone;
timsPhone = new DeskPhone(123456);
timsPhone.powerOn();
timsPhone = new MobilePhone(45678);
//Question begins here
timsPhone.powerOn();
timsPhone.powerOn();
}
}
ITelephone.java
public interface ITelephone {
void powerOn();
}
MobilePhone.java
public class MobilePhone implements ITelephone{
private int myNumber;
public MobilePhone(int myNumber) {
this.myNumber = myNumber;
}
#Override
public void powerOn() {
System.out.println("You are in MobilePhone class");
}
}
DeskPhone.java
public class DeskPhone implements ITelephone {
private int myNumber;
public DeskPhone(int myNumber) {
this.myNumber = myNumber;
}
#Override
public void powerOn() {
System.out.println("You are in DeskPhone class");
}
}
Assign the MobilePhone object to a different local variable.
In the current code, once the value of the timsPhone variable is replaced by the MobilePhone object, the DeskPhone object is unreachable and you cannot call its powerOn() method.
Suggested code:
ITelephone timsDeskPhone = new DeskPhone(123456);
timsDeskPhone.powerOn();
ITelephone timsMobilePhone = new MobilePhone(45678);
timsMobilePhone.powerOn();
timsDeskPhone.powerOn();
Output
You are in DeskPhone class
You are in MobilePhone class
You are in DeskPhone class
You might try to isolate in a static method the calling to your interface method..
public class Main {
public static void main(String[] args) {
phonePowerOn(new DeskPhone(123456));
phonePowerOn(new MobilePhone(45678));
}
static void phonePowerOn(ITelephone timsPhone){
if (timsPhone != null){
timsPhone.powerOn();
}
}
}
Either you misunderstood the question, it was a trick, or possibly a little of both. Were those first four lines of main given to you like that? Did they tell you that you can't change them? Then the tactful response might be adding a few lines strategically like this:
static void main(String[] args){
ITelephone timsPhone;
timsPhone = new DeskPhone(123456);
timsPhone.powerOn();
ITelephone timsDeskPhone = timsPhone;
timsPhone = new MobilePhone(45678);
ITelephone timsMobilePhone = timsPhone;
timsPhone = timsDeskPhone;
timsPhone.powerOn();
timsPhone = timsMobilePhone;
timsPhone.powerOn();
}
This meets their specifications and shows an understanding of interfaces and references. With a question like this, the code is only of secondary importance. I would think they're really trying to assess communication, response to stress, and maybe even creativity. So just immediately saying, "You can't do that" really isn't much better than one that throws a ClassCastException.
The fun way is to fight fire with fire:
public class MobilePhone implements ITelephone{
private int myNumber;
public MobilePhone(int myNumber) {
this.myNumber = myNumber;
}
private int powerOnCallCount = 0;
#Override
public void powerOn() {
if (powerOnCallCount == 0){
System.out.println("You are in DeskPhone class")
} else {
System.out.println("You are in MobilePhone class");
}
powerOnCallCount++;
}
}
Again, we've only added code, it meets their specifications, and shows the same understanding of interfaces and references.
Or course, a sarcastic answer like this usually won't win points with the interview panel, but has use in the right situation. Remember, they're on trial, too. If I've already tried to gently steer towards a solution like the first and they don't back down, now I'm getting suspicious of their technical knowledge and company culture. If I've noticed a few other yellow flags, then I'd consider something like this to turn the tables. The kind of company I'd want to work for would appreciate that I already tried the tactful approach, met their specifications without compromising technical knowledge, and had enough spine to try my own test on them. I'd probably only resort to it if I was already convinced I didn't want the job, but wanted to give them one last chance to win me over.
Plus, if they practice test driven design, they'd pretty much have to offer me the job right on the spot.
I am designing a game with multiple levels. I have a setup class that sets up the board based on the argument it receives, which indicates which level it should set up. Here is the class:
public class BoardState {
public BoardState(InitialState state) {
switch (state) {
case EMPTY:
setupEmptyState();
break;
case INTEGRATIONTEST:
setupIntegrationTestState();
break;
case LEVEL_1:
setupLevelOne();
break;
case LEVEL_2:
setupLevelTwo();
break;
default:
throw new Error("Invalid level selection");
}
}
private void setupEmptyState() { }
private void setupIntegrationTestState() { }
private void setupLevelOne() { }
private void setupLevelTwo() { }
}
This works fine, but every time I add a new level I have to add code in three places: The InitialState enum which defines the list of accepted states, the switch statement in the constructor, and the body of the class, where I have to add a method to set up the level in question.
One nice thing that I want to keep is the fact that my GUI automatically populates with a new button for each level I add based on the enum defining the list of levels.
How can I refactor this code so that there is less overhead associated with adding a new level?
Often when you need to reduce code duplication, an interface arise. This time (based on your comment in OP) it seems you need to add different objects to the board depending on which level you are:
import java.util.List;
public interface LevelSettings {
List<GameObject> startingObjects();
}
Now, BoardState looks like that (no more setupX() methods)
import java.util.List;
public class BoardState {
private final List<GameObject> gameObjects;
public BoardState(LevelSettings settings) {
this.gameObjects = settings.startingObjects();
}
}
Since you also specified it is nice for you to have an enum to dynamically creates buttons on the GUI, one can combine the best of both world (interface and enum) by implementing the interface in an enum...
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY {
#Override
public List<GameObject> startingObjects() {
return Collections.emptyList();
}
},
INTEGRATIONTEST {
#Override
public List<GameObject> startingObjects() {
GameObject g1 = new GameObject("dummy 1");
GameObject g2 = new GameObject("dummy 2");
return Arrays.asList(g1, g2);
}
},
LEVEL_1 {
#Override
public List<GameObject> startingObjects() {
//read a config file to get the starting objects informations
//or also hardcoded (not preferred)
}
},
LEVEL_2 {
#Override
public List<GameObject> startingObjects() {
//read a config file to get the starting objects
//or also hardcoded (not preferred)
}
};
}
And that's it basically. If you need to add LEVEL_3 do it in InitialState and everything will follow.
Going one step further
From here it goes beyond what you requested, feel free to ignore this part if you are not convinced.
As a good practice I would store these configurations only in config files to reduce even more the code duplication and gain in flexibility:
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY {
#Override
public List<GameObject> startingObjects() {
return readFromFile("empty.level");
}
},
INTEGRATIONTEST {
#Override
public List<GameObject> startingObjects() {
return readFromFile("integration_test.level");
}
},
LEVEL_1 {
#Override
public List<GameObject> startingObjects() {
return readFromFile("1.level");
}
},
LEVEL_2 {
#Override
public List<GameObject> startingObjects() {
return readFromFile("2.level");
}
};
private static List<GameObject> readFromFile(String filename) {
//Open file
//Serialize its content in GameObjects
//return them as a list
}
}
So that when you decide to add a new level you actually only need to know the filename in which the level's configuration is stored.
Going another step further
What you will see there is really tricky and I don't advice you to use it in production code (but it reduces code duplication) !
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY, INTEGRATIONTEST, LEVEL_1, LEVEL_2;
#Override
public List<GameObject> startingObjects() {
return readFromFile(this.name() + ".level");
}
private static List<GameObject> readFromFile(String filename) {
//Open file
//Serialize its content in GameObjects
//return them as a list
}
}
Here we rely on enum names themselves to find the corresponding correct file. This code works because it is based on the convention that the files are named accordingly to the enum names with the ".level" extension. When you need to add a new level, just add it to the enum and that's it...
You could use inheritance, polymorphism is the keyword here.
Set up your InitialState class as abstract base class (or interface if you have no common fields) and define a method public abstract void setup();.
abstract class InitialState {
public abstract void setup();
}
Then, for each of your original switch cases, derive a class from your base class, for example LevelOne, and implement its specific by overriding setup().
class LevelOne extends InitialState {
#Override
public void setup() {
// The code from "setupLevelOne()" goes here
}
}
Your BoardState class reduces to this:
public class BoardState {
public BoardState(InitialState state) {
// At runtime, the right method of the actual
// state type will be called dynamically
state.setup();
}
}
However, if you need to set interal state of your BoardState class, consider defining the setup method as public abstract void setup(BoardState boardState), so you can access its getter and setter methods.
This appraoch could also foster reuse of code, as you could add several abstract layers for different types of levels.
well you can refactor all of the work into a one method.
say it takes an int as the ID of the level, while it loads a JSON file containing structured information of each level, and creates the given level.
for example :
"levels" : [
"level" : {
"id" : "001",
"size" : "200",
"difficulty" : "2"
},
"level" : {
"id" : "002",
"size" : "300",
"difficulty" : "3"
}
]
then, in your code:
public void setupLevel(int id) throws levelNotFoundException{
//somehow like this
Document doc = parse("levels.json");
for(element elm: doc.get("levels")){
if(Integer.parseInt(elm.get("id")).equals(id)){
//setup your level
}
}
}
and then somewhere you call your method:
int levelId = getNextLevel();
try{
setupLevel(levelId);
} catch (LevelNotFoundException e){e.printStackTrace();}
or you can use XML, or simply hard code it, and store all levels in an array
I'm kinda new to Java, and I'm trying to write an RPG of sorts.
Now, in the game the player character would have skills. These could be very diverse, from hurting enemies to healing the player and a lot of other things. It'd make sense to create a Skill class with an abstract applyEffect() method, to be defined on each particular skill.
However, I cannot have a non-abstract class containing abstract methods, and every skill should be an object of the Skill class, so it can't be abstract. The obvious solution is to make the Skill class abstract and create a subclass for every single skill, and then instantiate that into an object to use.
This approach seems a bit redundant. Is there anything else I could conceivably do in this situation?
EDIT: While we're at it, if I want an object that will appear a single time with standard variables, is there any workaround to making a class just for that one object and then instantiating it?
I would not write skills (like 'heal' and 'hide') as classes. I view classes as objects (players), and methods as abilities (skills). Skills like 'heal' or 'hide' are clearly better as methods than classes.
I would simply have one class that has all methods, but only the selected ones are available for use. Having the skills as enums isn't a bad idea either.
enum Skill {
HEAL, HIDE, ATTACK, THROW
}
class Player {
boolean canHeal = false;
boolean canHide = false;
boolean canAttack = false;
boolean canThrow = false;
Player(Skill[] skills) {
for(skill : skills) {
switch(skill) {
case Skills.HEAL: canHeal = true;
break;
case Skills.HIDE: canHide = true;
break;
case Skills.ATTACK: canAttack = true;
break;
case Skills.THROW: canThrow = true;
break;
default: //error
}
}
}
void heal() {
[...]
}
void hide() {
[...]
}
void attack() {
[...]
}
void throw() {
[...]
}
boolean canHeal() {
return canHeal;
}
boolean canHide() {
return canHide;
}
boolean canAttack() {
return canAttack;
}
boolean canThrow() {
return canThrow;
}
}
Now the players can be restricted to only use the methods that should be available to them. What I would do is probably to write a GameHandler-class to take care of everything and do all the checking there.
How about this:
public abstract class Skill {
public abstract void applyEffect();
}
... somewhere else ...
Skill dig = new Skill() {
#Override
public void applyEffect() {
doSomeDigging();
}
};
This one still creates a subclass in the background, but you might like it better.
i would use enums also, you can stuff a bunch of login in them. the maps let each player have whatever skills and stats they need. you can nest enums like this or that.
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
public class So36107587 {
enum Stat {
food,health,magic;
}
enum Skill {
heal,hurt,hunt;
static void apply(Skill skill,double amount,Player player) {
double a=amount*random.nextDouble(),x;
switch(skill) {
case heal:
x=player.stats.get(Stat.health);
player.stats.put(Stat.health,a+x);
break;
case hurt:
x=player.stats.get(Stat.health);
player.stats.put(Stat.health,a-x);
break;
case hunt:
x=player.stats.get(Stat.food);
player.stats.put(Stat.food,a+x);
break;
}
}
static final Random random=new Random();
}
static class Player {
Player() {
init();
}
void init() {
for(Stat stat:Stat.values())
stats.put(stat,1.);
for(Skill skill:Skill.values())
skills.put(skill,1.);
}
void apply(Skill skill,Player player) {
Skill.apply(skill,skills.get(skill),player);
}
#Override public String toString() {
return ""+skills+" "+stats;
}
final Map<Stat,Double> stats=new TreeMap<>();
final Map<Skill,Double> skills=new TreeMap<>();
}
public static void main(String[] args) {
Player player=new Player();
System.out.println(player);
player.apply(Skill.heal,player);
System.out.println(player);
player.apply(Skill.hunt,player);
System.out.println(player);
}
}
I have a object graph which goes like this:
root
: childs (array)
: childs (array)
I am building a JSON response out of this so I need to loop through each collection creating code like this:
// code for root
// loop through direct root childs
for (Child child : childs) {
// Loop through the childs of the object in current context.
for (AnotherChild anotherChild : moreChilds) {
}
}
How do you avoid such code? It will be an arrow in the end. I could have created own methods for each level of for loop, but is that a good approach? Are there other approaches which is better?
If we are talking about this specific problem (building a JSON response) you use some kind of serializer like jackson or write a custom one. There is a relevant question on this topic https://stackoverflow.com/questions/338586/a-better-java-json-library
On the other hand for some other uses you can use a more functional approach like Guava or Lambdaj.
But when it comes done to big O complexity these are not much of a help there, so you may wanna try different approach if possible then.
That's a recursive structure, then you should use recursion to handle nesting. A depth first visit should do.
edit to interface JSON you would really follow the advice by #Mite Mitreski, for a recursive visit pseudocode sample:
void visit(Child tree) {
json_write_class(tree);
for (Attribute a : tree.attributes) {
json_write_attr(a);
if (tree.children != null) {
json_push_indent();
for (Child child : tree.children) {
visit(child);
}
json_pop_indent();
}
}
If you need more control, you could write kind of 'semantic actions' on nodes of that tree to establish the attributes, and implement the visitor pattern to output the data (more verbose than the first alternative).
Frequently helps to use the analogy of grammars and syntax trees, these are the most obvious sample we (as programmers) are used to.
I think you have a nasty design issue there, as the class that is doing all those loops knows a hell lot of the other classes (and thus breaking the Law of Demeter).
An approach I try to use (that I've learn from some very experienced developers) is to wrap collections (or arrays) in their own classes; and then create methods that iterate over the array/collection performing one operation. In this case, it could be calling another method in another class that wraps a collection.
In this way, each class has very little knowledge of what the other classes do (or the internals of the child objects).
Edit
Here's an example. Imagine that you have an account in a website similar to amazon. In that account, you have associated a few credit cards.
So, instead of having
class Account {
List<CreditCard> creditCards;
public CreditCard getPrimaryCard() {
//complex code to find the primary credit card
}
//lots of other code related to the account and credit cards
}
you can do
class Account {
CreditCards creditCards;
public CreditCard getPrimaryCard() {
creditCards.getPrimaryCard()
}
//lots of other code related to the account
}
class CreditCards {
List<CreditCard> creditCards;
public CreditCard getPrimaryCard() {
//complex code to find the primary credit card
}
public void addCard(CreditCard creditCard) {
//complex logic to validate that the card is not duplicated.
}
//lots of other code related to credit cards
}
In this way, Account doesn't need to know about how the creditCards are stored in memory (should it be a list? or a set? or get it from a remote webservice?)
Please bear in mind that this is a trivial example.
You could provide interface which all interested class should implement. That interface should provide method to converting a current object to JSON. See example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JsonProgram {
public static void main(String[] args) {
Root root = new Root(Arrays.asList(new Child(Arrays.asList(
new AnotherChild(1), new AnotherChild(2)))));
System.out.println(root.toJSON());
}
}
interface JsonState {
String toJSON();
}
class Root implements JsonState {
private List<Child> childs = new ArrayList<Child>();
public Root(List<Child> childs) {
this.childs = childs;
}
#Override
public String toJSON() {
StringBuilder builder = new StringBuilder();
builder.append("{").append("\"childs\"").append(":[");
int index = 0;
for (Child child : childs) {
builder.append(child.toJSON());
if (index < childs.size() - 1) {
builder.append(",");
}
index++;
}
builder.append("]\"}");
return builder.toString();
}
}
class Child implements JsonState {
private List<AnotherChild> anotherChilds = new ArrayList<AnotherChild>();
public Child(List<AnotherChild> anotherChilds) {
this.anotherChilds = anotherChilds;
}
#Override
public String toJSON() {
StringBuilder builder = new StringBuilder();
builder.append("{").append("\"anotherChilds\"").append(":[");
int index = 0;
for (AnotherChild child : anotherChilds) {
builder.append(child.toJSON());
if (index < anotherChilds.size() - 1) {
builder.append(",");
}
index++;
}
builder.append("]}");
return builder.toString();
}
}
class AnotherChild implements JsonState {
private int value;
public AnotherChild(int value) {
this.value = value;
}
#Override
public String toJSON() {
StringBuilder builder = new StringBuilder();
builder.append("{").append("\"value\"").append(":\"").append(value)
.append("\"}");
return builder.toString();
}
}
Output:
{
"childs":[
{
"anotherChilds":[
{
"value":"1"
},
{
"value":"2"
}
]
}
]
}
But it is not a good solution. Instead of implementing Your own solution You should use some library which can do it for You. I recommend to You google-gson. For me is the best.
EDIT - GSON EXAMPLE
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class JsonProgram {
public static void main(String[] args) {
Root root = new Root(Arrays.asList(new Child(Arrays.asList(
new AnotherChild(1), new AnotherChild(2)))));
Gson gson = new GsonBuilder().serializeNulls().create();
System.out.println(gson.toJson(root));
}
}
class Root {
private List<Child> childs = new ArrayList<Child>();
public Root(List<Child> childs) {
this.childs = childs;
}
#Override
public String toString() {
return Arrays.toString(childs.toArray());
}
}
class Child {
private List<AnotherChild> anotherChilds = new ArrayList<AnotherChild>();
public Child(List<AnotherChild> anotherChilds) {
this.anotherChilds = anotherChilds;
}
#Override
public String toString() {
return Arrays.toString(anotherChilds.toArray());
}
}
class AnotherChild {
private int value;
public AnotherChild(int value) {
this.value = value;
}
#Override
public String toString() {
return Integer.toString(value);
}
}
Above example create same output. For me this is a more elegant solution.
I'm designing a text-based adventure game for a school progress. I have each "level" set up as a class, and each explorable area (node) as a method within the appropriate class.
What's messing with me is the code to move from one node to another. Because each node is connected to up to four other nodes, I have to repeat an extremely similar block of code in each method.
What I'd prefer to do is include an array of methods at the beginning of each node, like this:
public static void zero()
{
... adjacentNodes[] = {one(), two(), three(), four()};
}
And then send that array to a generic method, and have it send the player to the right node:
public static void move(...[] adjacentNodes, int index)
{
adjacentNodes[index];
}
I simplified my code, but that's the general idea. Is this possible?
Whenever you think of pointer-to-function, you translate to Java by using the Adapter pattern (or a variation). It would be something like this:
public class Node {
...
public void goNorth() { ... }
public void goSouth() { ... }
public void goEast() { ... }
public void goWest() { ... }
interface MoveAction {
void move();
}
private MoveAction[] moveActions = new MoveAction[] {
new MoveAction() { public void move() { goNorth(); } },
new MoveAction() { public void move() { goSouth(); } },
new MoveAction() { public void move() { goEast(); } },
new MoveAction() { public void move() { goWest(); } },
};
public void move(int index) {
moveActions[index].move();
}
}
Just have your nodes be objects that all adhere to the same interface, then you'll be able to call their methods reliably.
Since Java does not have the concept of methods as first-class entities, this is only possible using reflection, which is painful and error-prone.
The best approximation would probably be to have the levels as enums with a per-instance implementation of a method:
public enum Level1 implements Explorable{
ROOM1 {
public void explore() {
// fight monster
}
}, ROOM2 {
public void explore() {
// solve riddle
}
}, ROOM3 {
public void explore() {
// rescue maiden
}
};
}
public interface Explorable{
public abstract void explore();
}
public static void move(Explorable[] adjacentNodes, int index)
{
adjacentNodes[index].explore();
}
However, this is a bit of an abuse of the enum concept. I wouldn't use it for a serious project.
Your design has fundamental flaws. Normal OO design would have each "level" be an object (of Class 'level' or something like it). each 'explorable area' would also be an object, contained within the level object - maybe of class ExplorableArea. The 'explorable areas' can be different kinds, in which case you make them different subclasses of ExplorableArea.
Try thinking about solutions without reflection. It's can be enums, for example.
I arrive late at the party with one possible approach, now you can use java.util.function (link) for this kind of problem.
To literally answer the question, regardless of its correctness, or applicability, here a possible version:
public static void zero()
{
Function<World, World> one = (World start) -> RoomWithMonster.in(start);
Function<World, World> two = (World start) -> EmptyRoom.in(start);
Function<World, World> three = (World start) -> RoomWithMonster.in(start);
Function<World, World> four = (World start) -> Treasure.in(start);
List<Function<World, World>> adjacentNodes = List.of(one, two, three, four);
return adjacentNodes;
}
public static void move(List<Function<World, World>> possibleNodes, int index)
{
World beginning = World.start();
World end = possibleNodes.get(index).apply(beginning);
}
This approach prefer immutability and add a little World class to abstract away the state of the game but still maintaining the question you wanted.
NB: fortunately now the reflection comments are obsolete!
You can use Reflection class to create an array of methods.
http://java.sun.com/developer/technicalArticles/ALT/Reflection/