Skip to main content
Commonmark migration
Source Link

##Removing Getters, Part 2: External Behaviour##

Removing Getters, Part 2: External Behaviour

##Removing Getters, Part 2: External Behaviour##

Removing Getters, Part 2: External Behaviour

public class Piece
{
    public Coordinate Position {get; private set;}
}

public class Coordinate
{
    public int X {get; private set;}
    public int Y {get; private set;}
}

    //...And then, inside some class
    public voidbool DoPiecesCollide(Piece one, Piece two)
    {
        return one.X == two.X && one.Y == two.Y;
    }
public class Piece
{
    public Coordinate Position {get; private set;}
}

public class Coordinate
{
    public int X {get; private set;}
    public int Y {get; private set;}
}

    //...And then, inside some class
    public void DoPiecesCollide(Piece one, Piece two)
    {
        return one.X == two.X && one.Y == two.Y;
    }
public class Piece
{
    public Coordinate Position {get; private set;}
}

public class Coordinate
{
    public int X {get; private set;}
    public int Y {get; private set;}
}

    //...And then, inside some class
    public bool DoPiecesCollide(Piece one, Piece two)
    {
        return one.X == two.X && one.Y == two.Y;
    }
added 701 characters in body
Source Link
Ben Aaronson
  • 7k
  • 1
  • 32
  • 30

(I'm going to be writing code examples in C# rather than Java, hopefullyfor brevity and because I'm more familiar with it. Hopefully that's not a problem. The concepts are the same and the translation should be simple.)

Note that this doesn't protect against other methods in the class mutating X and Y. To be more strictly immutable, you could use readonly (final in Java). But either way- whether you make your properties truly immutable or just prevent direct public mutation through setters- it does the trick of removing your public setters. In the vast majority of situations, this works just fine.

public class Piece
{
    public Coordinate Position {get; private set;}
}

public class Coordinate
{
    public int X {get; private set;}
    public int Y {get; private set;}
}

    //...InsideAnd then, inside some class
    public void DoPiecesCollide(Piece one, Piece two)
    {
        return one.X == two.X && one.Y == two.Y;
    }

ThisSo the above is a good start, but sooner or later you will probably run into a situation where you have behavior which is associated with a class, which in some way depends on the class's state, but which doesn't belong on the class. This sort of behavior is what typically lives in the service layer of your application.

As you can probably tell, _x and _y aren't really encapsulated any more. We could extract them by creating an IPositionTransformer<Tuple<int,int>> which just returns them directly. Depending on taste, you may feel this makes the entire exercise pointless. 

However, with public getters, it's actually simplervery easy to do itthings the rightwrong way, just pulling data out directly and using it in violation of Tell, Don't Ask. Whereas using this pattern enforces a certain amount of discipline in thatit's actually simpler to do it the right way: when you want to create behaviour, you'll automatically start by creating a type associated with it. Violations of TDA will be very obviously smelly and probably require working around a simpler, better solution. In practice, these points make it much, much easier to do it the right, OO, way than the "evil" way that getters encourage.

Finally, even if it isn't initially obvious, there may in fact be ways to expose enough of what you need as behavior to avoid needing to expose state, even if this isn't initially obvious. For example, using our previous version of Coordinate whose only public member is Equals() (in practice it would need a full IEquatable implementation), you could write the following class in your presentation layer:

It turns out, perhaps surprisingly, that all the behavior we really needed from a coordinate to achieve our goal was equality checking! Of course, this examplesolution is tailored to this problem, and makes assumptions about acceptable memory usage/performance. It's just an example that fits this particular problem domain, rather than a blueprint for a general solution. 

And again, opinions will vary on whether in practice this is needless complexity. In some cases, no such solution like this might exist, or it might be prohibitively weird or complex, in which case you can revert to the above three.

(I'm going to be writing code examples in C# rather than Java, hopefully that's not a problem. The concepts are the same and the translation should be simple.)

Note that this doesn't protect against other methods in the class mutating X and Y. To be more strictly immutable, you could use readonly (final in Java). But either way it does the trick of removing your public setters. In the vast majority of situations, this works just fine.

public class Piece
{
    public Coordinate Position {get; private set;}
}

public class Coordinate
{
    public int X {get; private set;}
    public int Y {get; private set;}
}

    //...Inside some class
    public void DoPiecesCollide(Piece one, Piece two)
    {
        return one.X == two.X && one.Y == two.Y;
    }

This is a good start, but sooner or later you will probably run into a situation where you have behavior which is associated with a class, which in some way depends on the class's state, but which doesn't belong on the class. This sort of behavior is what typically lives in the service layer of your application.

As you can probably tell, _x and _y aren't really encapsulated any more. We could extract them by creating an IPositionTransformer<Tuple<int,int>> which just returns them directly. Depending on taste, you may feel this makes the entire exercise pointless. However, it's actually simpler to do it the right way, and this pattern enforces a certain amount of discipline in that when you want to create behaviour, you'll automatically start by creating a type associated with it. In practice, these points make it much, much easier to do it the right, OO, way than the "evil" way that getters encourage.

Finally, there may in fact be ways to expose enough of what you need as behavior to avoid needing to expose state, even if this isn't initially obvious. For example, using our previous version of Coordinate whose only public member is Equals() (in practice it would need a full IEquatable implementation), you could write the following class in your presentation layer:

Of course, this example is tailored to this problem, and makes assumptions about acceptable memory usage/performance. And again, opinions will vary on whether in practice this is needless complexity. In some cases, no such solution like this might exist, or it might be prohibitively weird or complex, in which case you can revert to the above three.

(I'm going to be writing code examples in C# rather than Java, for brevity and because I'm more familiar with it. Hopefully that's not a problem. The concepts are the same and the translation should be simple.)

Note that this doesn't protect against other methods in the class mutating X and Y. To be more strictly immutable, you could use readonly (final in Java). But either way- whether you make your properties truly immutable or just prevent direct public mutation through setters- it does the trick of removing your public setters. In the vast majority of situations, this works just fine.

public class Piece
{
    public Coordinate Position {get; private set;}
}

public class Coordinate
{
    public int X {get; private set;}
    public int Y {get; private set;}
}

    //...And then, inside some class
    public void DoPiecesCollide(Piece one, Piece two)
    {
        return one.X == two.X && one.Y == two.Y;
    }

So the above is a good start, but sooner or later you will probably run into a situation where you have behavior which is associated with a class, which in some way depends on the class's state, but which doesn't belong on the class. This sort of behavior is what typically lives in the service layer of your application.

As you can probably tell, _x and _y aren't really encapsulated any more. We could extract them by creating an IPositionTransformer<Tuple<int,int>> which just returns them directly. Depending on taste, you may feel this makes the entire exercise pointless. 

However, with public getters, it's very easy to do things the wrong way, just pulling data out directly and using it in violation of Tell, Don't Ask. Whereas using this pattern it's actually simpler to do it the right way: when you want to create behaviour, you'll automatically start by creating a type associated with it. Violations of TDA will be very obviously smelly and probably require working around a simpler, better solution. In practice, these points make it much easier to do it the right, OO, way than the "evil" way that getters encourage.

Finally, even if it isn't initially obvious, there may in fact be ways to expose enough of what you need as behavior to avoid needing to expose state. For example, using our previous version of Coordinate whose only public member is Equals() (in practice it would need a full IEquatable implementation), you could write the following class in your presentation layer:

It turns out, perhaps surprisingly, that all the behavior we really needed from a coordinate to achieve our goal was equality checking! Of course, this solution is tailored to this problem, and makes assumptions about acceptable memory usage/performance. It's just an example that fits this particular problem domain, rather than a blueprint for a general solution. 

And again, opinions will vary on whether in practice this is needless complexity. In some cases, no such solution like this might exist, or it might be prohibitively weird or complex, in which case you can revert to the above three.

Bounty Awarded with 50 reputation awarded by IntelliData
added 487 characters in body
Source Link
Ben Aaronson
  • 7k
  • 1
  • 32
  • 30
Loading
added 25 characters in body
Source Link
Ben Aaronson
  • 7k
  • 1
  • 32
  • 30
Loading
Source Link
Ben Aaronson
  • 7k
  • 1
  • 32
  • 30
Loading