Interfaces are commonly used to achieve abstraction, not encapsulation. As per common definition for example from wiki:
Encapsulation refers to the bundling of data with the methods that operate on that data, or the restricting of direct access to some of an object's components, encapsulation is used to hide the values or state of a structured data object inside a class, preventing direct access to them by clients in a way that could expose hidden implementation details or violate state invariance maintained by the methods.
I.e. encapsulation is about hiding internal object data structure, not about restricting access to it's public methods based on context. In your current implementation encapsulation is achieved by the getter methods itself not by the fact of using an interface, i.e. internal implementation with fields is hidden from the end user by the provided methods. And interface in this case allows you to abstract your object to provide only valid public data in particular context.
I don't quite understand when to use interfaces.
Usually I recommend to think about interfaces as contracts which component implements and as any other abstraction - when correctly designed they allow to build less coupled systems which usually is considered a good thing. One of the biggest usecases for interfaces is to group related (or not that much) components when they needed to be used in the same way.
For example in this particular case if your system would work not only with people but with pets also you can have next abstractions:
interface IGetPublicInfo {...}
interface IGetSecretInfo { string GetSecret(); } // possibly not needed, but for the sake of interface segregation principle lets have it
interface IGetFullInfo : IGetSecretInfo, IGetPublicInfo {}
public class Person : IGetFullInfo {...} // specific person implementation
public class Pet : IGetFullInfo {...} // specific pet impl, for example secret is just "bark"
And then Friend
works with IGetFullInfo
public class Friend
{
private IGetFullInfo friend = new Person("Bob", 34); // or new Pet(...)
}
P.S.
Few small notes:
- You can have a slightly more succinct implementation with expression bodied properties
- Since strings are immutable in C# and int is a value type the
in
parameter modifier seems redundant in this case
public class Person : IGetPublicInfo
{
private string name;
private int age;
private string secret = "someSecret";
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public string Name => name;
public int Age => age;
public string Secret => secret;
}
interface IGetPublicInfo
{
string Name { get; }
int Age { get; }
}