Accessoren sind mehr als Felder. Andere haben bereits auf einige wichtige Unterschiede hingewiesen, und ich werde noch einen hinzufügen.
Eigenschaften nehmen an Schnittstellenklassen teil. Beispielsweise:
interface IPerson
{
string FirstName { get; set; }
string LastName { get; set; }
}
Diese Schnittstelle kann auf verschiedene Arten erfüllt werden. Beispielsweise:
class Person: IPerson
{
private string _name;
public string FirstName
{
get
{
return _name ?? string.Empty;
}
set
{
if (value == null)
throw new System.ArgumentNullException("value");
_name = value;
}
}
...
}
In dieser Implementierung schützen wir sowohl die Person
Klasse davor, in einen ungültigen Zustand zu gelangen, als auch den Aufrufer davor, null aus der nicht zugewiesenen Eigenschaft herauszuholen.
Aber wir könnten das Design noch weiter vorantreiben. Beispielsweise kann die Schnittstelle nicht mit dem Setter umgehen. Es ist durchaus legitim zu sagen, dass Verbraucher von IPerson
Schnittstellen nur daran interessiert sind, die Immobilie zu erhalten, nicht daran, sie festzulegen:
interface IPerson
{
string FirstName { get; }
string LastName { get; }
}
Die vorherige Implementierung der Person
Klasse erfüllt diese Schnittstelle. Die Tatsache, dass der Anrufer auch die Eigenschaften festlegen kann, ist aus Sicht der Verbraucher (die konsumieren IPerson
) bedeutungslos . Zusätzliche Funktionen der konkreten Implementierung werden beispielsweise vom Builder berücksichtigt:
class PersonBuilder: IPersonBuilder
{
IPerson BuildPerson(IContext context)
{
Person person = new Person();
person.FirstName = context.GetFirstName();
person.LastName = context.GetLastName();
return person;
}
}
...
void Consumer(IPersonBuilder builder, IContext context)
{
IPerson person = builder.BuildPerson(context);
Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}
In diesem Code weiß der Verbraucher nichts über Immobiliensetzer - es ist nicht seine Aufgabe, davon zu wissen. Der Verbraucher braucht nur Getter, und er bekommt Getter von der Schnittstelle, dh vom Vertrag.
Eine weitere vollständig gültige Implementierung IPerson
wäre eine unveränderliche Personenklasse und eine entsprechende Personenfabrik:
class Person: IPerson
{
public Person(string firstName, string lastName)
{
if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
throw new System.ArgumentException();
this.FirstName = firstName;
this.LastName = lastName;
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
}
...
class PersonFactory: IPersonFactory
{
public IPerson CreatePerson(string firstName, string lastName)
{
return new Person(firstName, lastName);
}
}
...
void Consumer(IPersonFactory factory)
{
IPerson person = factory.CreatePerson("John", "Doe");
Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}
In diesem Codebeispiel hat der Verbraucher erneut keine Kenntnis vom Ausfüllen der Eigenschaften. Der Verbraucher befasst sich nur mit Gettern, und die konkrete Implementierung (und die dahinter stehende Geschäftslogik, wie das Testen, ob der Name leer ist) bleibt den spezialisierten Klassen - Bauherren und Fabriken - überlassen. All diese Operationen sind mit Feldern absolut unmöglich.