If I try to inherit a builder to add more options, I get an unwanted requirement that options be set in a certain order. For example, let me build two builders for class java.awt.geom.Point2D. In the base builder, we can only set the X, but in the second builder, which extends the base builder, we can also set Y:
private static class PointBuilder{
private double x = 0.0;
protected double y = 0.0;
PointBuilder withX(double x) {
this.x = x;
return this;
}
Point2D build() {
return new Point2D.Double(x, y);
}
}
private static class PointBuilderWithY extends PointBuilder {
PointBuilder withY(double y) {
this.y = y;
return this;
}
}
public static void main(String[] args) {
Point2D pt1 = new PointBuilder()
.withX(5.0)
// .withY(3.0) // withY() doesn't compile, which is the intended behavior
.build();
// I can use a PointBuilderWithY only if I set the Y option first.
Point2D pt2 = new PointBuilderWithY()
.withY(3.0)
.withX(5.0)
.build();
// If I set the X option first, the Y option doesn't build!
Point2D pt3 = new PointBuilderWithY()
.withX(5.0)
.withY(3.0) // Won't compile! withX() didn't return a PointBuilderWithY
.build();
System.out.println(pt1);
System.out.println(pt2);
System.out.println(pt3);
}
If I call withX() before withY(), the withY() method won't compile, because the withX() method didn't return the PointBuilderWithY class. The base PointBuilder class doesn't have the withY() method.
I know that I can add an abstract withY() method to the base class, but that defeats the point. I want to limit the use of the withY() method to only those objects that need it. In other words, I want the compiler to enforce the restriction that withY() can't be called when using the first PointBuilder. At the same time, I don't want to tell my users that the options must be specified in a certain order, because that would be confusing. I prefer to write foolproof systems. Users expect to specify options in any order, which makes the class easier to use.
Is there a way to do this?
In PointBuilderWithY override all of PointBuilder's methods to return PointerBuilderWithY instances.
private static class PointBuilderWithY extends PointBuilder {
#Override
PointBuilderWithY withX(double x) {
return (PointBuilderWithY) super.withX(x);
}
PointBuilderWithY withY(double y) {
this.y = y;
return this;
}
}
So I've read about the pass-by-value nature of Java and I've tried to change my variable after passing it to a function by having the function return the variable again. I didn't succeed in that.
My code
public class Logic {
private int position;
public class Logic(){
position = 1;
}
public void appendPosition(){
position = calculatePosition(position);
}
}
This is the barebones code. I call this method from an instance of Logic which is instantiated in another class:
public class MainLogic {
ILogic L;
public MainLogic(ILogic L){
this.L = L;
}
public void start(){
L.appendPosition();
}
}
Through repeated debugging I find to my dismay that the position variable does not change at all. The position variable passed to calculatePosition changes fine, as expected. What am I missing? I've tried making the variable public and static.
calculatePosition
private int calculatePosition(int position){
position += 6;
if(snakeLocations[position]>0) {
position -= 6;
}
else if(ladderLocations[position]>0) {
position += 6;
}
return position;
}
private final int[] snakeLocations = new int[] {0,0,0,0,0,0,0,0,0,9,0,0,0,13,0,0,0,0,0,19,0,0,0,0,0};
private final int[] ladderLocations = new int[] {0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,15,0,0,0,0,20,0,0,0,0};
public class Logic {
private int position;
public Logic(){
position = 1;
}
//to get position.....................
public int getPosition(){
return this.position;
}
public void appendPosition(){
position = calculatePosition(position);
}
private int calculatePosition(int position){
position += 6;
if(snakeLocations[position]>0) {
position -= 6;
}
else if(ladderLocations[position]>0) {
position += 6;
}
return position;
}
private final int[] snakeLocations =
new int[] {0,0,0,0,0,0,0,0,0,9,0,0,0,13,0,0,0,0,0,19,0,0,0,0,0};
private final int[] ladderLocations =
new int[] {0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,15,0,0,0,0,20,0,0,0,0};
}
//next class
public class MainLogic {
Logic L;
public MainLogic(Logic L){
this.L = L;
}
public void start(){
L.appendPosition();
}
public static void main(String[] args) {
Logic L = new Logic();
MainLogic ml = new MainLogic(L);
System.out.println(ml.L.getPosition());
ml.start();
System.out.println(ml.L.getPosition());
}
}
Let's read your code.
// There is a logic class.
public class Logic {
// So Logic has a position. it starts with zero.
private int position;
// Logic also has an inner class, also called Logic.
public class Logic(){
position = 1;
// When a new Logic().Logic() is created, the instance
// variable of the parent instance gets set to one. WHAT?!?
}
// ... lots of code
}
So, It's a bit like that Yo Dawg! meme - I heard you like Logic, so we've put A logic instance into your Logic instance so you can Logic while your Logic.
You probably want a constructor.
// So this is Logic.
public class Logic {
private int position;
// When an Logic instance is created, position starts with 1.
public Logic(){
this.position = 1;
}
Ok. So we're not talking about Yo Dawg Memes.
So Let's talk pass by value.
Pass-by-value means classes are like very egotistic children: You can't play with their toys, unless they tell you so.
This is a good thingĀ® since this means only the owning instance is allowed to change their private state. Trust me, it prevents quite a bit of havoc.
One way to allow the outside world to actually change the state is by using query and mutator methods. Back in the day, we used to call them getter and setter, but that sounds too simple, so software architects will usually use the fancier term.
But... all of this doesn't really apply since calculatePosition() is defined at Logic. Oops.
Let's try this:
Renaming some instance variables
Be a bit verbose to help the debugger. baby steps.
(Also, dropping a few jokes to fish for upvotes).
public class Logic {
private int position = 1;
public void appendPosition(){
// When debugging strange stuff,
// keep each step simple.
// Is calculatePosition working as it should?
int newPosition = calculatePosition(this.position);
this.position = newPosition;
}
// Always use parameters as final. It's good karma.
// You don't NEED to declare them as final,
// but let's try to be EXTRA clear.
private int calculatePosition(final int targetPosition){
// Yes, make as much as you can immutable
// You'll save a ton of mental bandwidth.
final int localCopy = targetPosition +6;
if(snakeLocations[localCopy]>0) {
return (localCopy -6);
// Don't force the maintenance programmer to
// read all your stuff. Return often, return early.
// This isn't Cc++, where you need to
// actually free your reference/pointers,
// so there's no point enforcing a single return.
}
if(ladderLocations[localCopy]>0) {
return (localCopy+6);
}
return localCopy;
}
}
So... Did this worked as it should?
I found the answer. This is often my mistake in posting here. I try to strip down my code as much as possible to ease the work for you guys, but sometimes the problem lies outside of the scope of what I provide due to a lack of understanding, or oversight, on my part.
I was actually calling MainLogic from two levels above:
public mainFrame() {
initComponents();
logic = Factory.getMainLogic();
}
where
public static class Factory {
public MainLogic getMainLogic(){
PlayerLogic pL = new PlayerLogic();
ImageLogic iL = new ImageLogic();
DieLogic dL = new DieLogic();
MainLogic mainLogic = new MainLogic(pL,iL,dL);
return mainLogic;
}
}
I forgot I had accidentally put Factory as static. My sincerest apologies for wasting your time.
I intend to write a program that simulates particles collisions in one or more dimension. For the 2D case, I would also like to make a GUI that shows the particles.
I have a main class, ParticleCollider, which contains an inner class, Particle, an array of said Particlesas well as some methods for updating the positions and velocities of the particles. The class roughly looks like this:
class ParticleCollider {
class Particle {
private double mass;
private double[] pos;
//plus some other private class variables
public Particle(double mass, double[] pos) {
this.mass = mass;
this.pos = pos;
}
}
private Particle[] pArray;
//Details of constructor are irrelevant
public ParticleCollider() {
}
//Do stuff to particles in pArray, i.e. change their positions and velocitites
public void update() {
//For example
pArray[0].pos[0] = 0;
}
}
In the graphics class, I want to be able to access the Particles so that I can find their positions and radii for drawing purposes. One way would of course be to add a method getParticlesin ParticleColliderto return the array of Particles, pArray. My question is now if this would be considered a violation of encapsulation. Because the Particleclass has no setters, I cannot change the Particles. Also, because an array hase fixed length, I cannot add any Particles. The only thing I could do, which I guess is pretty bad, is take some Particleand assign it the value of null.
EDIT
It has been suggested that I use a List instead of an array and provide an iterator to said List. It would seem to me that this would not solve the encapsulation problem. Regardless, I'm relucant to abandon the array because I need to be able to select a random Particle in the collection of Particles and then iterate it cyclically.
How about using this pattern:
public class Particle {
// Particle code
}
public class Particles implements Iterable<Particle> {
ArrayList<Particle> myParticles = new ArrayList<Particle>();
public void add(Particle particle) { myParticles.add(particle); }
public Iterator<Particle> iterator() {
return myParticles.iterator();
}
// more code on particles
}
void bla() {
Particles particles = new Particles();
particles.add(new Particle());
particles.add(new Particle());
for (Particle particle : particles) {
System.out.println("P="+particle);
}
}
If you want to inhibit the remove() on this iterator you might use this pattern:
public static class Particles implements Iterable<Particle> {
ArrayList<Particle> myParticles = new ArrayList<Particle>();
public void add(Particle particle) { myParticles.add(particle); }
public Iterator<Particle> iterator() {
return new Iterator<Particle>() {
Iterator<Particle> listIterator = myParticles.iterator();
#Override
public boolean hasNext() {
return listIterator.hasNext();
}
#Override
public Particle next() {
return listIterator.next();
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
I am currently making a terrain generator, everything works fine in one class but I am going to be expanding my application.
Currently I have a JFrame class which holds everything, generating the terrain, painting the terrain, finding locations etc.
I want to add another class that will generate the terrain but when I create this class I need to access fields from the main JFrame class and when I do I get a stack overflow error - here is my code.
public class Simulator extends Applet
{
//fields
public Simulator()
{
grid = new int[100][100];
inhabGrid = new boolean[grid.length][grid.length];
gridSize = grid.length - 1;
dist = grid.length;
TerrainGenerator gen = new TerrainGenerator();
setSize(dist,dist);
seedGrid();
findInhabLocation();
printGridToConsole();
}
public void paint(Graphics g)
{
//panting the grid
}
public void seedGrid()
{
//seeding
}
public boolean generateTerrain(int x1,int y1, int x2, int y2)
{
//terrain generator
}
public boolean mouseUp(Event evt, int x, int y)
{
seedGrid(); //Create a new map
findInhabLocation();
repaint();
printGridToConsole();
return true;
}
public boolean keyEvents(Event evt, int x, int y)
{
seedGrid(); //Create a new map
findInhabLocation();
repaint();
printGridToConsole();
return true;
}
public void findInhabLocation()
{
//find best inhabitant location
}
public int locateWater(int x, int y)
{
//finding closest water
}
public int locateJungle(int x, int y)
{
//finding closest jungle
}
}
}
That works fine in its own class but when I create a class for example:
public class TerrainGenerator
{
Simulator sim = new Simulator();
}
I know this has something to do with the constructor and it's something silly I am doing, what would be the best way of splitting up this app into classes, for example terrain generator, inhabitants etc
For example I want to be able to call a method from the 'TerrainGenerator' class and call i.e. terrainGenerator.generateTerrain
Your TerrainGenerator creates a Simulator object and vice versa, hence you'll end up with infinitely many objects (but at some point the stack is full and a stack overflow exception is thrown instead...)
Instead of creating a new Simulator in your TerrainGenerator, you should pass a reference to your current Simulator (well, actually, that is not a great design either, but I'm not gonna confuse you with the problems of circular references).
Heuster answer is correct, furthermore, I think you could take look at MVC to help you organize your classes.
Depending which should be the parent, you can pass in the instantiated class to the other, ie;
private final TerrainGenerator gen; //if you need to save this.
public Simulator(TerrainGenerator terrainGenerator)
{
this.gen = terrainGenerator;
....etc
}
public class TerrainGenerator
{
Simulator sim = new Simulator(this);
}
or
private final TerrainGenerator gen; //if you need to save this.
public Simulator()
{
this.gen = new TerrainGenerator(this);
....etc
}
private final Simulator sim; //If you need to save it.
public class TerrainGenerator
{
public TerrainGenerator(Simulator simulator) {
this.sim = simulator;
}
}
I have a problem which isn't really that big, but still gives me some thought as to how Java constructors and methods are used.
I have a constant representing a radius I declare final, and also make it public for everyone to see. I don't want my code littered with getRadius() methods when I'm never ever going to change the radius.
I want to initialize the constant within the constructor as I want to apply certain criteria before assigning the radius, certain conditions have to be met. However, these conditions do take up some space, and I'd like to put them in some other method, to make the constructor cleaner.
The whole thing would initially look like this
public MyProblematicClass {
public final int radius;
public MyProblematicClass(... variables ...) {
if(... long criteria ...) {
radius = n;
}
}
}
and I'd love it to end up like
public MyProblematicClass {
public final int radius;
public MyProblematicClass(... variables ...) {
this.setRadiuswithCriteria(criteria);
}
private void setRadiuswithCriteria(criteria crit) {
if(... crit ...) {
radius = n;
}
I understand that I could potentially use the method for other purposes and that's the reason for giving me a 'blank field RADIUS may not have been initialized, so I'd like to know if there is a way to add a method which will only be used in constructors, for cleanliness's sake.
How about (using small caps for radius, because it is not a constant, as pointed out in the comments):
public MyProblematicClass(... variables ...) {
radius = getRadiusWithCriteria(criteria);
}
private int getRadiusWithCriteria(criteria crit) {
if(... crit ...) {
return n;
} else {
return 0;
}
}
You cannot assign to final variable outside constructor. As you said, method:
setRadiuswithCriteria(criteria crit) {
if(... crit ...) {
RADIUS = n;
}
Can be used outside constructor.
And you must set final variable to some value in constructor, not just after checking some criteria (always, not sometimes).
However, you might move the code outside the constructor, using the returned value of some function. Example:
class MyClass {
private final double i;
public MyClass() {
i = someCalculation();
}
private double someCalculation() {
return Math.random();
}
}
How about doing like this?
public MyProblematicClass {
public final int RADIUS;
public MyProblematicClass(... variables ...) {
RADIUS = this.setRadiuswithCriteria(criteria);
}
private int setRadiuswithCriteria(criteria crit) {
if(... crit ...) {
return n;
}
return 0;
}