Skip to content

Elegant Objects

Thomas Czogalik edited this page Jan 18, 2022 · 3 revisions

#Elegant Objects

Birth

never use -er name

  • do not name class after what class objects are doing.
  • name class after what it is
  • class is a Pixel, that can change color, not PixelColorChanger don't
class CashFormatter {
    private int dollars;
    CashFormatter(int dollar) {
        ...
    }
    public String format() {
        ...
    }
}

do

class Cash {
    private int dollars;
    Cash(int dollar) {
        ...
    }
    public String usDollar() {
        ...
    }
}

make on constructor primary

  • have many constructors and less methods
new Cash(30)
new Cash('30')
new Cash(30d)
new Cash(30f)
new Cash(30, 'USD')

keep contructor code free

  • init of object must be code-free -> instead wrap them
class Cash {
    private int dollars;
    Cash(String dollar) {
        this.dollars = Integer.parseInt(dollar)
    }
}
class Cash {
    private Number dollars;
    Cash(String dollar) {
        this.dollars = new StringAsInteger(dollar)
    }
}

class StringAsInteger implements Number{
    private String source;
    StringAsInteger(String source) {
        this.source = source
    }
    int intValue() {
        return Integer.parseInt(this.source)
    }
}
  • conversion is delayed until object initialization
  • first create object -> second allow it to work for us. Do not mix
App app = new App(new Data(), new Screen())
app.run()

Education

small objects are readable and maintainable

Encapsulate

  • as litte as possible
  • no more than 4 objects
  • in many languages state and identity are seperated
  • no encapsulation -> similar to static method

Interface

  • always use interfaces
  • no public method without interface, because user couples thightly with object

Method names

  • builder methods build something and return it (noun)
  • manipulator methods modify entity and return void (verb)
  • never mix

Do not use public constants

  • no constant classes
  • because class does not know what it is (no state, etc.)
class Constant {
    public static String Crlf = "\r\n"
}
  • use micro classes
class CrlfString {
    private String origin;
    CrlfString(String src) {
        this.origin = src
    }
    @Override
    String toString() {
        return String.format("%s\r\n", origin)
    }
}

Use Imutable

  • helps readablity
  • no identity mutability:
    • compare 2 objects -> change one of them -> you think they are still equal but are not
  • failure atomicity: Objects are always complete -> helps thread safty
  • side effect free
  • do not use null

Tests

  • Tests > Documentation
  • mocks make implementation hard to change
  • use fakes instead of mocks
    • in production code at best
interface Exchange {
    float rate(String origin, String target);
    final class Fake implements Exchange {
        @Override
        float rate(String origin, String target) {
            return 1.234;
        }
    }
}

@Test
void test() {
    Exchange exchange = new Exchange.Fake();
    Cash dollar = new Cash(exchange, 500);
    Cash euro = dollar.in("EUR");
    assert "6.17".euqals(euro.toString());
}

Employment

fewer than 5 public methods

  • the bigger the class the lower its maintainability

do not use static

object vs computer thinking

  • rather define than give instruction
class Max implements Number {
    private final Number a;
    private final Number b;
    public Max(Number left, Nuimber right) {
        this.a = left;
        this.b = right;
    }
}
// x "is a" maximum between 5 and 9
Number x = new Max(5,9);
// vs static (procedural)
int x = Math.max(5,9)

declarative vs imperative

  • imperative: statements that change program state
  • Declarative: express logic of computation without describing control flow
  • in declarative style user decides when he wants result -> lazy evaluation

Objects vs. Data Structures

  • objects trigger code execution
  • get and set prefix asume object is data structure

do not use null as parameter or return value

  • instead use exceptions, list, arrays, optionals (java)
  • use null classes
class NullUser implements User {
    private final String label;
    NullUser(String name) {
        this.label = name;
    }
    @Override
    public String name() {
        return this.label;
    }
    @Override
    public void raise(Chash salary) {
        // throw exception
    }
}

fail fast instead of fail save

  • reveal errors immediately
  • if someone uses api wrong he has to handle exception
Clone this wiki locally