How should I retain Encapsulation Principle of OOP, when using builder pattern? I mean fact that builder should provide abstraction layer between object and the code that uses it, so that it can be constructed part-by-part, requires either making setter for every parameter of an object that we would normally pass in the constructor. That again may be undesirable in some cases, as I don't want client to be able to modify value that I have to via builder. Example to picture what I mean is below:
public class Cat
{
private string _race;
private string _name;
public Cat()
{
_race = "common";
_name = string.Empty;
}
public void setRace(string race) { _race = race; }
public void setName(string name) { _name = name; }
}
public class CatBuilder
{
private Cat _objectUnderConstruction;
public CatBuilder() { _objectUnderConstruction = new Cat(); }
public CatBuilder WithName(string name)
{
_objectUnderConstruction.setName(name);
return this;
}
public CatBuilder OfRace(string race)
{
_objectUnderConstruction.setRace(race);
return this;
}
}
This is not production code, I wrote it now with presentation in mind, so do not get mad on how it is constructed.
In the example above there is need to set cat's race, as we need that information for the purpose of object filling, so we need to pass info into it. At the same time I don't want anyone to ever change race of my cat during its lifetime (e.g. it would change from egyptian to british in the middle of processing) Normally I would get rid of accessor method, but I need for the builder. This way, encapsulation of data is hurt (because straight get and set aren't encapsulating anything), and I want to avoid it.
This example is simple and I could pass parameter in constructor, but imagine bigger class, where there is a lot of such fields, what in this case? Should I pass some configuration object inside (which is almost like builder, but simpler, hence builder is pointless) or pass the builder itself to the constructor (which is weird, but what do I know)?
How I should do that?
If your builder is tightly-coupled with your class you can make Builder subclass of the object being constructed:
public class Cat
{
private string _race;
private string _name;
public Cat()
{
_race = "common";
_name = string.Empty;
}
private void setRace(string race) { _race = race; }
private void setName(string name) { _name = name; }
public class Builder
{
private Cat _objectUnderConstruction;
public CatBuilder() { _objectUnderConstruction = new Cat(); }
public CatBuilder WithName(string name)
{
_objectUnderConstruction.setName(name);
return this;
}
public CatBuilder OfRace(string race)
{
_objectUnderConstruction.setRace(race);
return this;
}
}
}
This way, you'll be able in Builder to access private fields and methods of Cat and use it like new Cat.Builder().OfRace("").OfName("").Build().
Related
I have the following interface:
public interface IStaff {
public StaffPosition getPosition();
public String toString();
}
and the class:
public class Worker implements IStaff {
private String name = null;
private String surname = null;
private int age = 0;
//StaffPosition is an enumeration class
private StaffPosition position= null;
public Worker (String name, String surname, int age, StaffPosition position){
this.name = name;
this.surname= surname;
this.age= age;
this.position= position;
}
#Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(this.name);
buffer.append(" ");
buffer.append(this.surname);
return buffer.toString();
}
#Override
public StaffPosition getPosition() {
return this.position;
}
public int getAge(){
return this.age;
}
In another class - Building, I have a HashMap<Office, IStaff> officeswhere Office is a normal class which only holds the number of the office and has a getter for that number.
And then in a yet another class Company I have an ArrayList<Building> buildings, which holds information about all the buildings of a company. In this class I need to get the age of a worker but how can I do that? So far I have a loop like this to get to the map:
for (Building building: buildings) {
for (Map.Entry<Office, IStaff> office: building.offices.entrySet()) {
//get the age of a worker
}
}
Is there a way to do that?
The only real answer is: when you need such an information in places where only your interface should show up, then that information needs to sit on the interface.
So your interface could have a method getAge(), or maybe getBirthday().
Side notes:
using I for "interface" in class names ... is bad practice, or at least: very much against java conventions.
you don't need to have a toString() in your interface. You get one from Object anyway.
(of course, there are dirty tricks, like doing an instanceof check somewhere, and then casting to the type of the concrete class. But as said: that is really bad practice)
Make IStaff an abstract class and then call the method.
Recently I came into a situation where the builder pattern was very strong, but I had the need to subclass. I looked up some solutions and some suggested generics while others suggested normal subclassing. However, none of the examples I looked at had required fields in order to even begin building an object. I wrote a tiny example to illustrate where I'm getting stuck. At every turn I kept running into a wall of problems where things would return the wrong class, can't override static methods, returning super() returns the wrong data type, etc. I have a feeling there is no way out except excessive use of generics.
What is the correct way to go in this situation?
Tester
import person.Person;
import person.Student;
public class Tester
{
public static void main(String[] args)
{
Person p = Person.builder("Jake", 18).interest("Soccer").build();
// Student s = Student.builder(name, age) <-- It's weird that we still have access to pointless static method
// Student s = Student.builder("Johnny", 24, "Harvard", 3).address("199 Harvard Lane") <-- returns Person builder, not student
Student s = ((Student.Builder)Student.builder("Jack", 19, "NYU", 1).address("Dormitory")).build(); // really bad
}
}
Person Class
package person;
import java.util.ArrayList;
import java.util.List;
public class Person
{
// Required
protected String name;
protected int age;
// Optional
protected List<String> interests = new ArrayList<>();
protected String address = "";
protected Person(String name, int age)
{
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
public List<String> getInterests() { return interests; }
public String getAddress() { return address; }
// person.person does not allow builder construction
// unless all required fields are provided
/* Problem: I have to repeat the constructor fields here, very annoying */
public static Builder builder(String name, int age)
{
Person p = new Person(name, age);
return new Builder(p);
}
public static class Builder
{
Person reference;
protected Builder(Person reference)
{
this.reference = reference;
}
public Builder address(String address)
{
reference.address = address;
return this;
}
public Builder interest(String interest)
{
reference.interests.add(interest);
return this;
}
public Person build()
{
return reference;
}
}
}
Student Class
package person;
import java.util.ArrayList;
import java.util.List;
public class Student extends Person
{
// Required
protected String school;
protected int year;
// Optional
protected List<String> subjects = new ArrayList<>();
// This looks good
public Student(final String name, final int age, final String school, final int year)
{
super(name, age);
this.school = school;
this.year = year;
}
public String getSchool() { return school; }
public int getYear() { return year; }
public List<String> getSubjects() { return subjects; }
/* Here's where my issues are:
* Override doesn't compile on static methods but how else can I describe that I want to
* override this functionality from the Person class?
*
* Extending 'Person' does not enforce that I need to provide 'name', 'age', etc like it would
* if this was a normal design pattern using the 'new' keyword. I have to manually drag fields
* from 'person' and place them here. This would get VERY messy with an additional class
*
* User can STILL call the Person builder on a Student object, which makes no sense. */
/*#Override*/ public static Builder builder(String name, int age, String school, int year)
{
Student s = new Student(name, age, school, year);
return new Builder(s);
}
public static class Builder extends Person.Builder
{
// Student reference; <--- this should not be needed since we already
// have a variable for this purpose from 'Person.Builder'
public Builder(final Student reference)
{
super(reference);
}
/* Things begins to get very messy here */
public Builder subject(String subject)
{
((Student)reference).subjects.add(subject);
// I guess I could replace the reference with a student one, but
// I feel like that infringes on calling super() builder since we do the work twice.
return this;
}
#Override public Student build()
{
// I can either cast here or
// rewrite 'return reference' every time.
// Seems to infringe a bit on subclassing.
return (Student)super.build();
}
}
}
What you write here :
Student s = ((Student.Builder)Student.builder("Jack", 19, "NYU", 1).address("Dormitory")).build(); // really bad
is indeed not very natural and you should not need to cast.
We expect rather something like :
Student s = Student.builder("Jack", 19, "NYU", 1).address("Dormitory")).build();
Besides all casts you did in the implementation of Student.Builder are also noise and statements that may fail at runtime :
/* Things begins to get very messy here */
public Builder subject(String subject) {
((Student)reference).subjects.add(subject);
return this;
}
#Override public Student build() {
return (Student)super.build();
}
Your main issue is the coupling between the Builder classes and the building methods.
A important thing to consider is that at compile time, the method binding (method selected by the compiler) is performed according to the declared type of the target of the invocation and the declared type of its arguments.
The instantiated type is considered only at runtime as the dynamic binding is applied: invoking the method bounded at compile time on the runtime object.
So this overriding defined in Student.Builder is not enough :
#Override public Student build() {
return (Student)super.build();
}
As you invoke :
Student.builder("Jack", 19, "NYU", 1).address("Dormitory").build();
At compile time, address("Dormitory") returns a variable typed as Person.Builder as the method is defined in Person.Builder :
public Builder address(String address){
reference.address = address;
return this;
}
and it not overriden in Student.Builder.
And at compile time, invoking build() on a variable declared as Person.Builder returns a object with as declared type a Person as the method is declared in Person.Builder as :
public Person build(){
return reference;
}
Of course at runtime, the returned object will be a Student as
Student.builder("Jack", 19, "NYU", 1) creates under the hood a Student and not a Person.
To avoid cast to Student.builder both from the implementation and the client side, favor composition over inheritancy :
public static class Builder {
Person.Builder personBuilder;
private Student reference;
public Builder(final Student reference) {
this.reference = reference;
personBuilder = new Person.Builder(reference);
}
public Builder subject(String subject) {
reference.subjects.add(subject);
return this;
}
// delegation to Person.Builder but return Student.Builder
public Builder interest(String interest) {
personBuilder.interest(interest);
return this;
}
// delegation to Person.Builder but return Student.Builder
public Builder address(String address) {
personBuilder.address(address);
return this;
}
public Student build() {
return (Student) personBuilder.build();
}
}
You can now write :
Student s = Student.builder("Jack", 19, "NYU", 1)
.address("Dormitory")
.build();
or even that :
Student s2 = Student.builder("Jack", 19, "NYU", 1)
.interest("Dance")
.address("Dormitory")
.build();
Composition introduces generally more code as inheritancy but it makes the code
both more robust and adaptable.
As a side note, your actual issue is enough close to another question I answered 1 month ago.
The question and its answers may interest you.
A few thoughts as background
Static methods are not so great,
they make unit testing more difficult.
It is fine to put the builder as a static, nested class, but if you are using a builder to construct a class you should make the constructor not-public.
I prefer to have the builder be a separate class in the same package and to make the constructor (of the class that is created by the builder) package access.
Limit the builder constructor parameters.
I'm not a fan of using a class hierarchy for builders.
The Person and Student classes each have a builder.
Some Code
public class PersonBuilder
{
private String address;
private int age;
private final List<String> interestList;
private String name;
public PersonBuilder()
{
interestList = new LinkedList<>();
}
public void addInterest(
final String newValue)
{
// StringUtils is an apache utility.
if (StringUtils.isNotBlank(newValue))
{
interestList.add(newValue);
}
return this;
}
public Person build()
{
// perform validation here.
// check for required values: age and name.
// send all parameters in the constructor. it's not public, so that is fine.
return new Person(address, age, interestList, name);
}
public PersonBuilder setAddress(
final String newValue)
{
address = newValue;
return this;
}
public PersonBuilder setAge(
final int newValue)
{
age = newValue;
return this;
}
public PersonBuilder setInterestList(
final List<String> newValue)
{
interestList.clear();
if (CollectionUtils.isNotEmpty(newValue))
{
interestList.addAll(newValue);
}
return this;
}
public PersonBuilder setName(
final String newValue)
{
name = newValue;
return this;
}
}
public class Person
{
private Person()
{
}
Person(
final String addressValue,
final int ageValue,
final List<String> interestListValue,
final String name)
{
// set stuff.
// handle null for optional parameters.
}
// create gets or the fields, but do not create sets. Only the builder can set values in the class.
}
So, here is an typical implementation of Memento pattern (skipped getters and setters).
public class Employee {
private String name;
private String phone;
public EmployeeMemento save() {
return new EmployeeMemento(name, phone);
}
public void revert(EmployeeMemento memento) {
this.name = memento.getName();
this.phone = memento.getPhone();
}
}
public class EmployeeMemento {
private final String name;
private final String phone;
public EmployeeMemento(String name, String phone) {
this.name = name;
this.phone = phone;
}
}
public class Caretaker {
private Stack<EmployeeMemento> history;
public Caretaker() {
history = new Stack<>();
}
public void save(Employee employee) {
history.push(employee.save());
}
public void revert(Employee employee) {
employee.revert(history.pop());
}
}
All implementations of this pattern that I found are more or less equal to the one above. But there are some problems about this kind of implementation, that I don't like:
It's possible to triger both employee.revert() and caretaker.revert(employee). I would like to have only one access point.
If we want to change EmployeeMemento, we have to make changes in Employee class also (because of revert method).
Is there a way to overcome this?
Or maybe I pay too much attention, and this details are not so important?
1) Note that Caretaker is supposed to take care of holding Mementos, not necessarily take care of Undo/Redo. If you look at the various implementations on Internet (For example here), you'll see that Caretaker does not have revert() but usually something like getMemento(). So the class that takes care of Undoing, is someone else which calls getMemento() on Caretaker and then revert() on Subject.
Even if you want Caretaker to take care of Undoing, note that employee.revert() is a method that's solely created to be used by caretaker.revert(), because in this design, no one else has access to Mementos. You can reduce it's visibility to be visible by only Caretaker. (If this was C++, it would be easily done by use of friend, but in Java you have to be creative and use package visibility or some other way.)
2) In Memento pattern, a class and its Memento are tightly coupled. Actually it's only the class itself that has access to Memento's internals and no one else should see how Memento is composed. So it does not matter if a change to class, propagates to its Memento.
Then again If you want to isolate changes, you can be creative again. For example instead of duplicating name and phone in both Class and its Memento, you could extract another class which contains these fields (let's say by the name of State) and then use this State in both the original class and its Memento. This way, when you have changes to state of the class, you need only to modify State.
Side note: It's better to define Memento as a nested static class inside the Subject.
So my design, that addresses your issues, would be something like this:
public class Employee {
private State state;
public Memento save() {
return new Memento(state);
}
public void revert(Memento memento) {
this.state = memento.state;
}
public static class Memento {
private final State state;
public Memento(State state) {
this.state = state;
}
}
public static class State {
private String name;
private String phone;
}
}
public class Caretaker {
private Stack<Employee.Memento> history;
public Caretaker() {
history = new Stack<>();
}
public void addMemento(Employee.Memento memento) {
history.push(memento);
}
public Employee.Memento getMemento() {
return history.pop();
}
}
public class UndoHandler {
Employee employee;
Caretaker caretaker;
public void snapshot() {
caretaker.save(employee.save());
}
public void undo() {
employee.revert(caretaker.getMemento());
}
}
I have a case when I want to avoid defensive copies, for data which might nevertheless be modified, but is usually simply read, and not written to. So, I'd like to use immutable objects, with functional mutator methods, which is kind of usual (java lombok is able to do it more or less automatically). The way I proceed is the following:
public class Person {
private String name, surname;
public Person(String name, String surname) {....}
// getters...
// and instead of setters
public Person withName(String name) {
Person p= copy(); // create a copy of this...
p.name= name;
return p;
}
public Person copy() {....}
}
So, to get a copy of the person with a different name, I would call
p= new Person("Bar", "Alfred");
...
p= p.withName("Foo");
In practice, the objects are rather large (and I ended up using serialization to avoid the burden of writing the copy code).
Now, while browsing the web, I see a potential concurrency problem with this implementation, as my fields are not final, and thus, concurrent access might see the returned copy, for instance, without the new name change (as there is no warrantee on the order of operation in this context).
Of course, I can't make my fields final, with the current implementation, as I first do a copy, and then change the data in the copy.
So, I'm looking for a good solution for this problem.
I might use volatile, but I feel it's not a good solution.
Another solution would be to use the builder pattern:
class PersonBuilder {
String name, surname; ....
}
public class Person {
private final String name, surname;
public Person(PersonBuilder builder) {...}
private PersonBuilder getBuilder() {
return new PersonBuilder(name, surname);
}
public Person withName(String name) {
PersonBuilder b= getBuilder();
b.setName(name);
return new Person(b);
}
}
Is there any problem here, and above all, is there a more elegant way of doing the same thing ?
I recommend you take a look at Guava's immutable collections, such as immutable list and how they create lists from builders etc.
The idiom is the following:
List<String> list1 = ImmutableList.of("a","b","c"); // factory method
List<String> list2 = ImmutableList.builder() // builder pattern
.add("a")
.add("b")
.add("c")
.build();
List<String> list3 = ... // created by other means
List<String> immutableList3 = ImmutableList.copyOf(list3); // immutable copy, lazy if already immutable
I really like the idiom above. For an entity builder I would take the following approach:
Person johnWayne = Person.builder()
.firstName("John")
.lastName("Wayne")
.dob("05-26-1907")
.build();
Person johnWayneClone = johnWayne.copy() // returns a builder!
.dob("06-25-2014")
.build();
The builder here can be obtained from an existing instance via the copy() method or via a static method on the Person class (a private constructor is recommended) that return a person builder.
Note that the above mimics a little Scala's case classes in that you can create a copy from an existing instance.
Finally, don't forget to follow the guidelines for immutable classes:
make the class final or make all getters final (if the class can be extended);
make all fields final and private;
initialize all fields in the constructor (which can be private if you provide a builder and/or factory methods);
make defensive copies from getters if returning mutable objects (mutable collections, dates, third party classes, etc.).
One possibility is to separate your interfaces surrounding such objects into an immutable variant (providing getters) and a mutable variant (providing getters and setters).
public interface Person {
String getName();
}
public interface MutablePerson extends Person {
void setName(String name);
}
It doesn't solve the mutability of the object per se but it does offer some guarantees that when you pass around the object using the immutable interface reference, you know that the code you're passing this to won't change your object. Obviously you need to control the references to the underlying object and determine the subset of functionality that has control of a reference via the mutable interface.
It doesn't solve the underlying problem and I would favour immutable objects until I definitely need a mutable version. The builder approach works nicely, and you can integrate it within the object to give a modifier thus:
Person newPerson = existingPerson.withAge(30);
Why not make your fields final and your modifier methods directly create new objects?
public class Person {
private final String name, surname;
public Person(String name, String surname) {....}
// getters...
// and instead of setters
public Person withName(String newName) {
return new Person(newName, surname);
}
}
Your problem boils down to this: You want a method that safely publishes an effectively immutable, almost-but-not-quite-faithful copy of an effectively immutable object.
I'd go with the builder solution: It's verbose as all get out, but Eclipse helps with that, and it allows all of the published objects to be actually immutable. Actual immutability makes safe publication a no-brainer.
If I wrote it, it'd look like this:
class Person {
public static final FooType DEFAULT_FOO = ...;
public static final BarType DEFAULT_BAR = ...;
public static final BazType DEFAULT_BAZ = ...;
...
private final FooType foo;
private final BarType bar;
private final BazType baz;
...
private Person(Builder builder) {
this.foo = builder.foo;
this.bar = builder.bar;
this.baz = builder.baz;
...
}
public FooType getFoo() { return foo; }
public BarType getBar() { return bar; }
public BazType getBaz() { return baz; }
...
public Person cloneWith(FooType foo) {
return new Builder(this).setFoo(foo).build();
}
public Person cloneWith(BarType bar) {
return new Builder(this).setBar(bar).build();
}
public Person cloneWith(FooType foo, BarType bar) {
return new Builder(this).setFoo(foo).setBar(bar).build();
}
...
public class Builder{
private FooType foo;
private BarType bar;
private BazType baz;
...
public Builder() {
foo = DEFAULT_FOO;
bar = DEFAULT_BAR;
baz = DEFAULT_BAZ;
...
}
public Builder(Person person) {
foo = person.foo;
bar = person.bar;
baz = person.baz;
...
}
public Builder setFoo(FooType foo) {
this.foo = foo;
return this;
}
public Builder setBar(BarType bar) {
this.bar = bar;
return this;
}
public Builder setBaz(BazType baz) {
this.baz = baz;
return this;
}
...
public Person build() {
return new Person(this);
}
}
}
Depends on how many fields you intend to change. You could make special Changed objects like:
interface Person {
public String getForeName();
public String getSurName();
}
class RealPerson implements Person {
private final String foreName;
private final String surName;
public RealPerson (String foreName, String surName) {
this.foreName = foreName;
this.surName = surName;
}
#Override
public String getForeName() {
return foreName;
}
#Override
public String getSurName() {
return surName;
}
public Person setSurName (String surName) {
return new PersonWithSurnameChanged(this, surName);
}
}
class PersonWithSurnameChanged implements Person {
final Person original;
final String surName;
public PersonWithSurnameChanged (Person original, String surName) {
this.original = original;
this.surName = surName;
}
#Override
public String getForeName() {
return original.getForeName();
}
#Override
public String getSurName() {
return surName;
}
}
This may also mitigate the problem you have with cloning heavy objects.
Well, i was trying to pass arraylist of objects from one activity to another. I have 2 constructors in the class Student.
If, i use, Serializable than the code is like below:
#SuppressWarnings("serial")
public class Student implements Serializable
{
private int studentdID;
private String studentName;
private String studentDept;
public Student(){}
public Student(String name, String dpt)
{ this.studentName = name;
this.studentDept = dpt;}
public Student(int id, String name, String dpt)
{ this.studentdID = id;
this.studentName = name;
this.studentDept = dpt; }
public int getstudentdID() { return studentdID; }
public void setstudentdID(int studentdID) {this.studentdID = studentdID;}
public String getstudentName() { return studentName;}
public void setstudentName(String studentName) {this.studentName = studentName;}
public String getstudentDept() { return studentDept; }
public void setstudentDept(String studentDept) { this.studentDept = studentDept;}
}
But the problem i am facing is that how am i going to do this with parcelable? How am i going to set the values of the variables in class-like i did with Serializable? I mean separately using 2 constructors-one without ID another without the ID?
Did you read how Parcelable works?
You need only one constrcutor for parcelable to read what you pass to it, and Parcelable interface will add a method writeToParcel where you put the data to save.
It's not an automatic process like Serializable, everything is up to you.
The constructor which Parcelable will use will accept only one argument Parcel where you will find some methods like read*(KEY) to read back values.
And in writeToParcel you will write in the Parcel (the argument of the method) the values you want pass to pass with write*(KEY, VALUE).
Parcelable don't care about your constructors or fields.
P.S You will need a CREATOR too. Read some tutorial online to know more about it if you need.
Marco's answer explains why Parcelable doesn't automatically decide what constructor to use - it can't.
However, there is a way around this. Use Parcel.dataAvail(), which
Returns the amount of data remaining to be read from the parcel. That
is, dataSize()-dataPosition().
For example,
public Student(){}
public Student(String name, String dpt)
{
this.studentName = name;
this.studentDept = dpt;}
public Student(int id, String name, String dpt)
{ this.studentdID = id;
this.studentName = name;
this.studentDept = dpt;
}
public Student(Parcel in) {
name = in.readString();
dpt = in.readString();
if(in.dataAvail() > 0) // is there data left to read?
id = in.readInt();
}
^ The above constructor will allow for the necessary variables to be instantiated correctly. Also, you define writeToParcel() something like:
public void writeToParcel(Parcel out) {
out.writeString(name);
out.writeString(dpt);
//0 is the default value of id if you didn't initialize it like
// in the first constructor. If it isn't 0, that means it was initialized.
if(id != 0)
out.writeInt(id);
}
Of course, you'll need to define your CREATOR like so:
public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
public Student createFromParcel(Parcel in) {
return new Student(in);
}
public Student[] newArray(int size) {
return new Student[size];
}
};
#u3l solution is not required..how many constructors are there it doesn't matter.
simple it works go as normal implementation.
I mean no special care is required when multiple constructors present in parcelable.