Skip to content

Commit 2487e3d

Browse files
author
Nicolai Parlog
committed
[01] Demonstrate static factory methods
1 parent e37ec50 commit 2487e3d

File tree

6 files changed

+199
-0
lines changed

6 files changed

+199
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,8 @@ Related links:
99
* [Amazon USA](https://amzn.to/2QI0D0S)
1010
* [Amazon Germany](https://amzn.to/2OvsWOu)
1111
* visit [courses.codefx.org](http://courses.codefx.org) for online courses on Java
12+
13+
## Creating and destroying objects
14+
15+
* Item 1: [Consider static factory methods instead of constructors](https://www.youtube.com/watch?v=WUROOKn2OTk) -
16+
[examples](src/main/java/org/codefx/demo/effective_java/_01_static_factory_methods/Main.java)

pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
<maven.compiler.target>10</maven.compiler.target>
1414
</properties>
1515

16+
<dependencies>
17+
<dependency>
18+
<groupId>com.google.guava</groupId>
19+
<artifactId>guava</artifactId>
20+
<version>25.0-jre</version>
21+
</dependency>
22+
</dependencies>
23+
1624
<build>
1725
<plugins>
1826
<plugin>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.codefx.demo.effective_java._01_static_factory_methods;
2+
3+
/*
4+
* You will find NOTEs on the following topics:
5+
* - basics
6+
* - named constructors
7+
* - instance-control
8+
* - type-control
9+
*/
10+
11+
public class Main {
12+
13+
public static void main(String[] args) {
14+
namedConstructors();
15+
instanceControl();
16+
typeControl();
17+
}
18+
19+
// private static void before() {
20+
// // NOTE basics:
21+
// // * the code must read `new $CLASS` - no way to give it a nice name
22+
// // * the code will create a new instance - no way to, e.g., cache instances
23+
// // * the code will create a `Point` - no way to create a more suitable subtype
24+
// Point origin = new Point(0, 0);
25+
// Point somePoint = new Point(42, 63);
26+
// Rectangle rectangle = new Rectangle(origin, somePoint);
27+
// System.out.println(rectangle);
28+
// }
29+
30+
private static void namedConstructors() {
31+
Point origin = Point.ofXY(0, 0);
32+
Point upperRight = Point.ofXY(42, 63);
33+
Rectangle someRectangle = Rectangle.fromLowerLeftToUpperRight(origin, upperRight);
34+
35+
Point onXAxis = Point.ofXY(0, 63);
36+
Point onYAxis = Point.ofXY(42, 0);
37+
Rectangle otherRectangle = Rectangle.fromUpperLeftToLowerRight(onXAxis, onYAxis);
38+
39+
System.out.println(someRectangle + " vs " + otherRectangle);
40+
}
41+
42+
private static void instanceControl() {
43+
Point origin = Point.ofXY(0, 0);
44+
Point otherOrigin = Point.ofXY(0, 0);
45+
if (origin == otherOrigin)
46+
System.out.println("There can only be one origin!");
47+
48+
Point somePoint = Point.ofXY(4, 2);
49+
Point otherPoint = Point.ofXY(4, 2);
50+
if (somePoint == otherPoint)
51+
System.out.println("There can only be one 4/2!");
52+
}
53+
54+
private static void typeControl() {
55+
Point origin = Point.ofXY(0, 0);
56+
Point upperRight = Point.ofXY(42, 42);
57+
Rectangle square = Rectangle.fromLowerLeftToUpperRight(origin, upperRight);
58+
59+
if (square instanceof Square)
60+
System.out.println(square);
61+
}
62+
63+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.codefx.demo.effective_java._01_static_factory_methods;
2+
3+
import com.google.common.cache.Cache;
4+
import com.google.common.cache.CacheBuilder;
5+
6+
import java.util.concurrent.ExecutionException;
7+
8+
public class Point {
9+
10+
// NOTE instance-control: ORIGIN is a constant
11+
private static final Point ORIGIN = new Point(0, 0);
12+
// NOTE instance-control: Points can be cached
13+
private static final Cache<Integer, Cache<Integer, Point>> POINTS_BY_X_Y = CacheBuilder.newBuilder().build();
14+
15+
private final int x, y;
16+
17+
// NOTE basics: The constructor is private to avoid accidental use; this also prevents subclassing
18+
private Point(int x, int y) {
19+
this.x = x;
20+
this.y = y;
21+
}
22+
23+
// NOTE instance-control: The method's contract clarifies that there is no guarantee regarding identity
24+
/**
25+
* @return A {@code Point} instance with the specified x/y coordinates (not necessarily a new instance)
26+
*/
27+
// NOTE named constructors:
28+
// * `ofXY` explains very well what the parameters mean;
29+
// * `Rectangle`'s static factories are even more informative
30+
// NOTE basics: A static factory method is `static` and returns an instance of the type (Duh!)
31+
public static Point ofXY(int x, int y) {
32+
if (x == 0 && y == 0)
33+
return ORIGIN;
34+
// NOTE instance-control: Only points with specific properties (in the 20x20 box around origin) care cached
35+
if (Math.abs(x) <= 10 && Math.abs(y) <= 10)
36+
try {
37+
return POINTS_BY_X_Y
38+
.get(x, () -> CacheBuilder.newBuilder().build())
39+
.get(y, () -> new Point(x, y));
40+
} catch (ExecutionException e) {
41+
// do nothing, ignore the cache, and construct a new point
42+
}
43+
return new Point(x, y);
44+
}
45+
46+
public int x() {
47+
return x;
48+
}
49+
50+
public int y() {
51+
return y;
52+
}
53+
54+
@Override
55+
public String toString() {
56+
return "(" + x + "/" + y + ")";
57+
}
58+
59+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.codefx.demo.effective_java._01_static_factory_methods;
2+
3+
import static org.codefx.demo.effective_java._01_static_factory_methods.Point.ofXY;
4+
5+
public class Rectangle {
6+
7+
protected final Point lowerLeft, upperRight;
8+
9+
// NOTE basics: Constructor is protected to make accidental use less likely while allowing subclassing
10+
protected Rectangle(Point lowerLeft, Point upperRight) {
11+
this.lowerLeft = lowerLeft;
12+
this.upperRight = upperRight;
13+
}
14+
15+
public static Rectangle fromLowerLeftToUpperRight(Point lowerLeft, Point upperRight) {
16+
// NOTE type-control: the code determines at run time what type to return
17+
if (upperRight.x() - lowerLeft.x() == upperRight.y() - lowerLeft.y())
18+
return new Square(lowerLeft, upperRight.x() - lowerLeft.x());
19+
return new Rectangle(lowerLeft, upperRight);
20+
}
21+
22+
// NOTE named constructors:
23+
// Thanks to static factories, it is easy to distinguish the two ways to construct a `Rectangle`
24+
public static Rectangle fromUpperLeftToLowerRight(Point upperLeft, Point lowerRight) {
25+
Point lowerLeft = ofXY(upperLeft.x(), lowerRight.y());
26+
Point upperRight = ofXY(lowerRight.x(), upperLeft.y());
27+
return fromLowerLeftToUpperRight(lowerLeft, upperRight
28+
);
29+
}
30+
31+
@Override
32+
public String toString() {
33+
return "[↙" + lowerLeft + " & ↗" + upperRight + "]";
34+
}
35+
36+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.codefx.demo.effective_java._01_static_factory_methods;
2+
3+
import static org.codefx.demo.effective_java._01_static_factory_methods.Point.ofXY;
4+
5+
// NOTE type-control: `Square` is package-visible, i.e. not part of the public API
6+
class Square extends Rectangle {
7+
8+
protected final int edgeLength;
9+
10+
protected Square(Point lowerLeft, int edgeLength) {
11+
super(lowerLeft, computeUpperRight(lowerLeft, edgeLength));
12+
this.edgeLength = edgeLength;
13+
}
14+
15+
private static Point computeUpperRight(Point lowerLeft, int edgeLength) {
16+
return ofXY(lowerLeft.x() + edgeLength, lowerLeft.y() + edgeLength);
17+
}
18+
19+
public static Square ofLowerLeftAndEdgeLength(Point lowerLeft, int edgeLength) {
20+
return new Square(lowerLeft, edgeLength);
21+
}
22+
23+
@Override
24+
public String toString() {
25+
return "[↙" + lowerLeft + " & ⇿" + edgeLength + "]";
26+
}
27+
28+
}

0 commit comments

Comments
 (0)