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.
Related
I created a factory pattern in my class.
In this class I injected classes which implements Command interface based on incoming String parameter.
Factory class
#Component
#RequiredArgsConstructor
public class CommandFactory {
private final ACommand aCommand;
private final BCommand bCommand;
private final CCommand cCommand;
private final DCommand dCommand;
private final ECommand eCommand;
private final FCommand fCommand;
public Command createCommand(String content) {
if (aCommand.isMatching(content)) {
return aCommand;
} else if (bCommand.isMatching(content)) {
return bCommand;
} else if (cCommand.isMatching(content)) {
return cCommand;
} else if (dCommand.isMatching(content)) {
return dCommand;
} else if (eCommand.isMatching(content)) {
return eCommand;
} else if (fCommand.isMatching(content)) {
return fCommand;
} else {
return null;
}
}
In isMatching() method there are different regex'es and I try to figure out how this incoming String should be processed.
I am looking for a cleaner way to get rid of these sequential if statements. Because whenever I create a new class into this factory I add another if statement.
Maybe Stream can help?
Stream<Command> stream = Stream.of(aCommand, bCommand, cCommand ...);
return stream.filter(x -> x.isMatching(content)).findFirst().orElse(null);
Now every time you add a new class, you just add a new object to the first line.
If you want to get rid of the sequential if statements you can use streams (like user Sweeper suggested) or loops and I would also suggest to return and optional which makes null handling clearer for the client.
Here are two suggested options to get rid of if else repetitions one with loops another with streams:
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class CommandPatternExample {
private List<Command> candidates = Arrays.asList(new ACommand(), new BCommand(), new CCommand());
public Optional<Command> createCommand(String content) {
for(Command command : candidates) {
if(command.isMatching(content)) {
return Optional.of(command);
}
}
return Optional.empty();
}
public Optional<Command> createCommandStream(String content) {
return candidates.stream().filter(c -> c.isMatching(content)).findFirst();
}
}
interface Command<T> {
void execute(T obj);
boolean isMatching(String s);
}
class ACommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "A".equals(s);
}
}
class BCommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "B".equals(s);
}
}
class CCommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "C".equals(s);
}
}
Map might be a good idea. Meaning if you place your command instances into a map as values where your key would be something that you could match against incoming String. Then instead of sequential search with Efficiency O(n) you can get much better performance O(1). This is a short answer.
Besides that There is an open source java library MgntUtils (wriiten by me) that contains some utility called "Self-instantiating factories" Basically it manages and the Factory for you. All you will need to do is to create a class that implements a certain interface and the utility will add it for you into a map based factory. It might be useful to you. Here is the link to an article that explains about the utilities in the library as well as where to get the library (Github and Maven central). In the article look for the paragraph "Lifecycle management (Self-instantiating factories)". Also library comes with a detailed written javadoc and code example for that feature.
I have a problem with the following code:
Import java.util.ArrayList;
public class Car {
private String car;
private Car genCar = new Car();
ArrayList<String> allCars = new ArrayList<>();
public void setCar() {
genCar.setModel();
genCar.setCreator();
car = genCar.getModel() + "made by" + genCar.getCreator();
}
public void checkDouble() {
for (String search : allCars) {
while (search.equals(car)) {
setCar();
}
}
allCars.add(car);
}
public void repeater(){
for(int i = 0; i<52; i++){
setCar();
checkDouble();
}
}
}
Whenever I try to check for duplicates (which this code does) my program still puts the duplicate in the array when I actually try to avoid it this way.
Any solution so this works?
You do this:
public void checkDouble()
{
for (String search : allCars)
{
while (search.equals(car))
{
setCar();
}
}
allCars.add(car);
}
The problem with this is that, once you found a double, you generate a new car using setCar(), but you do not search the entire list again.
Do something like:
public void avoidDoubles()
{
while allCars.contains(car)
{
setCar(); // generate new, different car
}
allCars.add(car);
}
FWIW, you might want to change the name of some of the functions. I would call setCar() generateNewCar() or newCar().
I'm not sure what you're trying to do, but in checkDouble you are finding a duplicate and then adding it to the list.
If I understand you correctly, you don't need the loops, All you need to do is to use ArrayList.contains()
if(allCars.contains(someString))
{
System.err.println("Duplicate...");
} else
{
//setCar, addCar, etc.
}
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
We had a scenario where we had to sort a object based on name and also the List Object inside that based on name. Please find the below Java objects.
Make class
class Make implements comparable<Make> {
String name;
List<Model> models;
....
getter..
setters..
#Override
public intcompareTo(object o) {
return name.compareTo(o.name);
}
}
Model Class
class Model implements comparable<Model> {
String name ;
....
getter..
setters..
#Override
public intcompareTo(object o) {
return name.compareTo(o.name);
}
}
Main Class
class main {
public static void main(String[] args) {
List<Make> make = new ArrayList<Make>();
Make make1 = new Make();
make1.addName("B");
Model model1 = new Model()
model1.setName ("B");
make1.addModel(model1);
Model model2 = new Model()
model2.setName ("A");
make1.addModel(model2);
make.add(make1);
// This will sort the make Object but not the model.
collections.sort(make);
}
}
We wanted to sort both Make and Model on Name.
How to sort both the make Models in the above scenario.?
Iterate through each Make object element and sort it's List field
for(Make makeElement : make)
{
Collections.sort(makeElement.models);
}
Personally I would go with #James solution.
but if you really really want to sort everything with one call (NOTE internally is many many calls :) )
change Make.intcompareTo(object 0) to :
public intcompareTo(object 0)
{
if(models!=null){
Collection.sort(models);
}
return name.compareTo(o.name);
}
Immutable classes are great but there is one big problem i cant think of a sensible way to solve - cycles.
class Friend {
Set<Friend> friends();
}
How does one model Me having You as a friend who in turn has me as a Friend back ?
IMMUTABILITY
This class from the outside world should definitely be immutable. The value held internally should be constant for the purposes of equality checks.
[[[ Edit: Added code to demonstrate fully immutable concept ]]]
That's why builders are so nice for immutables - they allow mutability during construction to get everything set before you "freeze" it. In this case, I guess you need a Friend builder that supports creating cycles.
final FriendBuilder john = new FriendBuilder().setName("john");
final FriendBuilder mary = new FriendBuilder().setName("mary");
final FriendBuilder susan = new FriendBuilder().setName("susan");
john
.likes(mary)
.likes(susan);
mary
.likes(susan)
.likes(john);
susan
.likes(john);
// okay lets build the immutable Friends
Map<Friend> friends = FriendsBuilder.createCircleOfFriends(john, mary, susan);
Friend immutableJohn = friends.get("john");
Edit: Added immutable example below to demonstrate approach:
There was some discussion in the comments about whether an immutable version was possible.
Fields are final and immutable. A modifiable set is used in the constructor, but it only the unmodifiable reference is kept after construction.
I have another version that uses Guava ImmutableSet for a truly immutable set rather than JDK's unmodifiable wrapper. It works the same, but uses Guava's nice set builder.
Code:
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
/**
* Note: potentially cycle graph - be careful of deep equals/hashCode/toString/etc.
* Immutable
*/
public class Friend {
public static class Builder {
private final String name;
private final Set<Builder> friends =
new HashSet<Builder>();
Builder(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public Set<Builder> getFriends() {
return friends;
}
void likes(final Builder... newFriends) {
for (final Builder newFriend : newFriends)
friends.add(newFriend);
}
public Map<String, Friend> createCircleOfFriends() {
final IdentityHashMap<Builder, Friend> existing =
new IdentityHashMap<Builder, Friend>();
// Creating one friend creates the graph
new Friend(this, existing);
// after the call existingNodes contains all the nodes in the graph
// Create map of the all nodes
final Map<String, Friend> map =
new HashMap<String, Friend>(existing.size(), 1f);
for (final Friend current : existing.values()) {
map.put(current.getName(), current);
}
return map;
}
}
final String name;
final Set<Friend> friends;
private Friend(
final Builder builder,
final Map<Builder, Friend> existingNodes) {
this.name = builder.getName();
existingNodes.put(builder, this);
final IdentityHashMap<Friend, Friend> friends =
new IdentityHashMap<Friend, Friend>();
for (final Builder current : builder.getFriends()) {
Friend immutableCurrent = existingNodes.get(current);
if (immutableCurrent == null) {
immutableCurrent =
new Friend(current, existingNodes);
}
friends.put(immutableCurrent, immutableCurrent);
}
this.friends = Collections.unmodifiableSet(friends.keySet());
}
public String getName() {
return name;
}
public Set<Friend> getFriends() {
return friends;
}
/** Create string - prints links, but does not traverse them */
#Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append("Friend ").append(System.identityHashCode(this)).append(" {\n");
sb.append(" name = ").append(getName()).append("\n");
sb.append(" links = {").append("\n");
for (final Friend friend : getFriends()) {
sb
.append(" ")
.append(friend.getName())
.append(" (")
.append(System.identityHashCode(friend))
.append(")\n");
}
sb.append(" }\n");
sb.append("}");
return sb.toString();
}
public static void main(final String[] args) {
final Friend.Builder john = new Friend.Builder("john");
final Friend.Builder mary = new Friend.Builder("mary");
final Friend.Builder susan = new Friend.Builder("susan");
john
.likes(mary, susan);
mary
.likes(susan, john);
susan
.likes(john);
// okay lets build the immutable Friends
final Map<String, Friend> friends = john.createCircleOfFriends();
for(final Friend friend : friends.values()) {
System.out.println(friend);
}
final Friend immutableJohn = friends.get("john");
}
}
Output:
Node 11423854 {
value = john
links = {
susan (19537476)
mary (2704014)
}
}
Node 2704014 {
value = mary
links = {
susan (19537476)
john (11423854)
}
}
Node 19537476 {
value = susan
links = {
john (11423854)
}
}
The correct way to model a cycle is with a Graph. And a single source code line comment can be enough to enforce inmutability: "can't touch this".
What kind of inmutable enforcement are you looking for? Do you want a a velociraptor to appear whenever you modify the inmutable Set? The difference between mutable and inmutable is just a convention. However, the bits on the RAM can be easily modified and with the Reflection API you can break any encapsulation and data hiding conventions.
Ignoring the velociraptor for a moment, Java does not support an inmutable type. As a workaround, you need to model a datatype that behaves like one.
And for the inmutable property to make sense you need to make Friend an interface, having one implementing class: InmutableFriend, and the construction of the object should fully happen inside the constructor.
Then, since the graph contains cycles, before creating the final inmutable instances you need to store the graph nodes in some mutable temporary structure. You also need to return an unmodifiableSet on the InmutableFriend.friends() method.
Finally, to clone the graph you need to implement a Deep-copy algorithm like Breadth-first search on the Mutable graph. One question though is what happens when the graph is not fully connected.
interface Friend {
public Set<Friend> friends();
}
class MutableFriend {
private Set<MutableFriend> relations = new HashSet<MutableFriend>();
void connect(MutableFriend otherFiend) {
if (!relations.contains(otherFriend)) {
relations.add(otherFiend);
otherFriend.connect(this);
}
}
Friend freeze() {
Map<MutableFriend, InmutableFriend> table = ...;
/*
* FIXME: Implement a Breadth-first search to clone the graph,
* using this node as the starting point.
*
* TODO: If the graph is not connected this won't work.
*
*/
}
}
class InmutableFriend() implements Friend {
private Set<Friend> connections;
public Set<Friend> friends() {
return connections;
}
public InmutableFriend(Set<Friend> connections) {
// Can't touch this.
this.connections = Collections.unmodifiableSet(connections);
}
}
Immutability doesn't need to be compiler-enforced to be valid architecturaly. You can have a legitimate immutable object that takes post-construction initialization parameters. For instance...
private Object something;
public void init( final Object something )
{
if( this.something != null )
{
throw new IllegalStateException();
}
this.something = something
}
The member field "something" isn't final, but it cannot be set more than once either.
A more complex variant based on discussion in comments...
private boolean initialized;
private Object a;
private Object b;
public void init( final Object a, final Object b )
{
if( this.initialized )
{
throw new IllegalStateException();
}
this.initialized = true;
this.a = a;
this.b = b;
}
public Object getA()
{
assertInitialized();
return this.a;
}
public Object getB()
{
assertInitialized();
return this.b;
}
private void assertInitialized()
{
if( this.initialized )
{
throw new IllegalStateException( "not initialized" );
}
}