Is creating an interface to a class a way to prevent to access the setters of this same class?

79 Views Asked by At

Let's say I have the class User with the attributes name, email etc.. In my code, I still want to be able to update that information, but I don't want anyone being able to reach the setters methods directly.

public class User implements UserOperations {

    private String name;

    public User(String name) {
        this.name = name
    }
 
    public String getName() {
        return name 
    }
 
    public void setName(String name) {
        this.name;
    }
}
public interface UserOperations {

     String getName();
}

Is creating an interface with only the getters methods a good idea or should I change the access-capabilities of the User's method from public to private or protected?

I tried to implement the interface, but I feel as if it's not the best solution there is.

3

There are 3 best solutions below

1
anteastra On

SOLID principles are the key answer for your concernes. In a way you want to separate logic of managing the state and managing operations you should create much more classes.

Here is possible solution: Your class User is pojo now. Making User class immutable will make impossible to change objects of this class.

To perform changes on object you would need to create a new object with new internal state. Usually it would be done with some other class as a facade which will perform required operations and return new object.

Effectively you would need some class UserOperationManager which will handle all required access to object

This approach will cover single responsibility and interface segregation principle

0
Basil Bourque On

The Answer by anteastra, and the Comment by Mark Rotteveel, are both correct.

Produce an immutable object, with a copy of current state

If your app has some places where User should be mutable, and other places where User should be immutable, then make another class for the immutable situation.

If the main purpose of this other class is to transparently communicate immutable data, use a record.

public record UserImmutable ( String name ) implements UserOperations 
{
    public String getName() {
        return this.name ;
    }
}

Add a toUserImmutable() method to your mutable class. This method produces an instance of our record with data based on the current state of our mutable object.

public class User implements UserOperations {

    private String name;

    public User(String name) {
        this.name = name ;
    }
 
    public String getName() {
        return name ;
    }
 
    public void setName(String name) {
        this.name ;
    }

    public UserImmutable toUserImmutable() {
        return new UserImmutable( this.name ) ;
    }
}

Usage:

UserImmutable userImmutable = user.toUserImmutable() ;  // Capture an immutable copy of the mutable object’s state. 

Or, use the more general interface.

UserOperations userImmutable = user.toUserImmutable() ;  // Capture an immutable copy of the mutable object’s state. 

Of course your immutable copy is just that, a copy. If the original mutable object changes its state, the immutable copy does not change. Whether that is a good thing or a bad thing depends on the specifics of your app’s situation.

0
Evgeny Smagin On

As already said above it is better to use immutable state (mark the fields final) and exclude setter, if still for some reason you need to leave setter, then you can make it private and use it in those methods that are declared in the public interface