Prostym sposobem na osiągnięcie tego byłoby posiadanie interfejsu, który pozwala czytać właściwości i wywoływać metody tylko do odczytu oraz klasę, która implementuje ten interfejs, co pozwala również na pisanie tej klasy.
Twoja metoda, która go tworzy, zajmuje się tym pierwszym, a następnie zwraca ten drugi, zapewniając tylko interfejs tylko do odczytu do interakcji. Nie wymagałoby to kopiowania i pozwala łatwo dostroić zachowania, które mają być dostępne dla dzwoniącego, a nie dla twórcy.
Weź ten przykład:
public interface IPerson
{
public String FirstName
{
get;
}
public String LastName
{
get;
}
}
public class PersonImpl : IPerson
{
private String firstName, lastName;
public String FirstName
{
get { return firstName; }
set { firstName = value; }
}
public String LastName
{
get { return lastName; }
set { lastName = value; }
}
}
class Factory
{
public IPerson MakePerson()
{
PersonImpl person = new PersonImpl();
person.FirstName = 'Joe';
person.LastName = 'Schmoe';
return person;
}
}
Jedyną wadą tego podejścia jest to, że można go po prostu rzucić na klasę wdrażającą. Gdyby to była kwestia bezpieczeństwa, samo zastosowanie tego podejścia jest niewystarczające. Obejściem tego problemu jest to, że można utworzyć klasę elewacji, aby owinąć klasę zmienną, która po prostu przedstawia interfejs, z którym program wywołujący współpracuje i nie może mieć dostępu do obiektu wewnętrznego.
W ten sposób nawet casting nie pomoże. Oba mogą wywodzić się z tego samego interfejsu tylko do odczytu, ale rzutowanie zwróconego obiektu da ci tylko klasę Fasada, która jest niezmienna, ponieważ nie zmienia stanu podstawowego opakowanej klasy zmiennej.
Warto wspomnieć, że nie jest to zgodne z typowym trendem, w którym niezmienny obiekt jest budowany raz na zawsze za pośrednictwem jego konstruktora. Zrozumiałe, że możesz mieć do czynienia z wieloma parametrami, ale powinieneś zadać sobie pytanie, czy wszystkie te parametry muszą zostać zdefiniowane z góry, czy też niektóre mogą zostać wprowadzone później. W takim przypadku należy zastosować prosty konstruktor z tylko wymaganymi parametrami. Innymi słowy, nie używaj tego wzorca, jeśli ukrywa on inny problem w twoim programie.