Інкапсуляція означає, що стан об'єкта відбувається лише через визначений інтерфейс, і завдяки цьому клас може переконатися, що цей стан завжди є дійсним і відповідає цілям класу.
Тому в деяких випадках цілком відповідає принципу інкапсуляції просто публічно виставити поле - усі можливі значення поля є дійсними з усіма іншими можливими значеннями всіх інших полів, і тому програміст може активно вирішити дозволити поле вільно маніпулювати зовнішнім кодом.
Ці випадки, однак, в основному обмежені класами, які в основному є "звичайними старими даними". Вони також не дуже цікаві в цьому плані, тому досить про них.
В інших випадках, іншими мовами, можна було б отримати метод getter та setter, щось на зразок int getId()отримання значення та void setId(int val)оновлення його.
Властивості дозволяють використовувати той самий синтаксис для читання та запису за допомогою таких методів, як і для читання та запису поля. Це хороший синтаксичний цукор, хоча і не життєво важливий.
(Насправді, завдяки тому, як працює відображення, і таким випадкам DataBinder.Evalможе бути зручно мати властивість, навіть коли поле буде працювати нормально, але це вже інша справа).
Доти, поки не будуть введені приватні сетери (насправді, те, що змінилося з C # 2, - це синтаксис наявності приватного сеттера та публічного або захищеного геттера в тому самому блоці), ми могли б мати приватний метод для виконання роботи приватного сеттера, тому приватні сетери насправді не потрібні. Вони, однак, дуже зручні, тому, хоч і є синтаксичним цукром, вони досить корисні.
Інкапсуляція - це питання не того, чи є ваші установники (або отримувачі) державними, приватними, захищеними чи внутрішніми, а питанням того, чи є вони доречними . Почніть із за замовчуванням кожного поля, яке є приватним (і з цього приводу readonly), а потім за необхідності додайте члени (властивості чи методи), які змінюють ці поля, і переконайтесь, що об’єкт залишається дійсним у міру їх зміни . Це гарантує збереження інваріанта класу , а це означає, що правила, що описують дійсний набір станів, в яких він може перебувати, ніколи не порушуються (конструктори також допомагають, переконавшись, що він починається в такому допустимому стані).
Що стосується вашого останнього питання, бути незмінним означає, що клас не має загальнодоступних, захищених чи внутрішніх установників та жодних загальнодоступних, захищених чи внутрішніх методів, які змінюють будь-які поля. Існують такі ступені, у C # можливі три ступені:
Усі поля екземпляра класу є readonly, отже, навіть приватний код не може його змінити. Він гарантовано буде незмінним (все, що намагається змінити, не компілюється) і, можливо, оптимізація може бути зроблена на звороті цього.
Клас незмінний ззовні, оскільки жоден публічний учасник нічого не змінює, але не гарантується використанням, readonlyщоб він не змінювався зсередини.
Клас незмінний, як це видно ззовні, хоча деякий стан є зміною як деталлю реалізації. Наприклад, поле може бути записане в пам'ять, і, отже, ззовні спроба отримати його просто отримує одне і те ж значення, перша така спроба насправді обчислює його, а потім зберігає для отримання при наступних спробах.
private File settingsFile = null;а потім в одному з конструкторів:if (settingsFile == null) { settingsFile = GetSettingsFile() };. Такий код рефакторингу змушував мене іноді плакати :). Те, що ви можете встановити члена перед конструктором, не означає, що вам слід це робити, оскільки для декількох конструкторів це ТВЕРДО слідувати логіці. Приватні установники змушують встановлювати значення всередині конструктора або пізнішої версії.