Immutability ...Don't Lose Your Train Of Thoughts
/**
* A nice little enum defining our shipping methods
*/
public enum ShippingMethod
{
US_CANADA(0),
INTERNATIONAL(10);
private final int fee;
/**
* @param fee how much does it cost
*/
private ShippingMethod(int fee)
{
this.fee = fee;
}
/**
* @return the fee of the shipping method
*/
public int fee() {
return this.fee;
}
}
/**
* You can use a class too!
*/
public final class ShippingMethodImpl
{
public static final ShippingMethodImpl US_CANADA = new ShippingMethodImpl(0);
public static final ShippingMethodImpl INTERNATIONAL = new ShippingMethodImpl(10);
private final int fee;
/**
* No need to have the constructor public.
*
* @param fee how much does it cost
*/
private ShippingMethodImpl(int fee)
{
this.fee = fee;
}
/**
* @return the fee of the shipping method
*/
public int fee() {
return this.fee;
}
}
/**
* Hopefully we don't send out international orders for free!
*/
public class ShippingMethodTest
{
@Test
public void enumz() throws Exception
{
ShippingMethod usCanada = ShippingMethod.US_CANADA;
ShippingMethod international = ShippingMethod.INTERNATIONAL;
Assert.assertEquals(0, usCanada.fee());
Assert.assertEquals(10, international.fee());
}
@Test
public void classes() throws Exception
{
ShippingMethodImpl usCanada = ShippingMethodImpl.US_CANADA;
ShippingMethodImpl international = ShippingMethodImpl.INTERNATIONAL;
Assert.assertEquals(0, usCanada.fee());
Assert.assertEquals(10, international.fee());
}
}
Class relationships are really important and noone wants a “complicated” one. Now although grammar does help sometimes it is still hard to decide which class should relate to which thus you end up not thinking too much about it and dump them on a need to have basis.
One way to think of classes is in terms of the object state they enforce. So in essence you have classes of two kinds. Muttable (the value of its fields can change) and immutable (you can tell from their final fields; see Disclaimer). It’s good practice not to mix the two since mixing a mutable with an immutable will give you a mutable one at the end :(.
The reason you should strive to design immutable classes is that are easier to maintain, (no state to worry about!) encourage reusability (objects are effectively constants!) and last but not least are thread safe. (woohoo, no concurrency bugs!)
Let’s take a look at the survival kit to identify classes that qualify for immutable. The text talks about 2 distinct shipping methods. US_CANADA and INTERNATIONAL. See a pattern here? With ShippingMethod as your class, you can have 2 objects, one for US_CANADA and second one for INTERNATIONAL. Yes constants (use CAPITAL to get your point across). In Java you can use an Enum for defining constants.
Summary:
- Start with private final fields.
- Don’t have (possible) immutable classes with mutable properties.
- Make constants out of your immutable classes and reuse them.
There is still a long way to go before we start sending survival kits out, so leave your feedback below on how you would specify any further class relationships, now that you have acquired that extra knowledge.
Also, Misko Hevery gives you another clue as to how to think about your class relatiosnhips when it comes to dependency injection
Disclaimer
Not strictly true. final is about not changing the reference of an object while the object itself might still change. Take an array for example, though you might not be able to assign a different one, you can still change its contents.