Деякі припустили, що речі можуть вийти з-під контролю за допомогою друга. Я погодився б, але це не зменшує його корисності. Я не впевнений, що друг обов'язково завдає шкоди парадигмі ОО, ніж оприлюднювати всіх членів вашого класу. Звичайно, мова дозволить вам оприлюднити всіх своїх членів, але це дисциплінований програміст, який уникає такого типу дизайну. Так само дисциплінований програміст зарезервував би використання друга для конкретних випадків, коли це має сенс. Я відчуваю, що в деяких випадках внутрішнє викриття занадто багато. Навіщо виставляти клас або метод усьому в зборі?
У мене є сторінка ASP.NET, яка успадковує мою власну базову сторінку, яка в свою чергу успадковує System.Web.UI.Page. На цій сторінці у мене є код, який обробляє повідомлення про помилки кінцевого користувача для програми захищеним методом
ReportError("Uh Oh!");
Тепер у мене є контроль користувача, який міститься на сторінці. Я хочу, щоб управління користувачам могло викликати методи повідомлення про помилки на сторінці.
MyBasePage bp = Page as MyBasePage;
bp.ReportError("Uh Oh");
Це не може зробити, якщо захищений метод ReportError. Я можу зробити його внутрішнім, але він піддається будь-якому коду в складі. Мені просто хочеться, щоб він потрапив до елементів інтерфейсу, які є частиною поточної сторінки (включаючи дочірні елементи управління). Більш конкретно, я хочу, щоб мій базовий клас управління визначав такі самі методи подання повідомлень про помилки та просто називав методи на базовій сторінці.
protected void ReportError(string str) {
MyBasePage bp = Page as MyBasePage;
bp.ReportError(str);
}
Я вважаю, що щось на зразок друга може бути корисним і реалізованим у мові, не роблячи мову менш "OO", як, можливо, як атрибути, так що ви можете мати класи або методи бути друзями до конкретних класів або методів, що дозволяє розробнику надавати дуже конкретний доступ. Можливо, щось на кшталт ... (псевдо-код)
[Friend(B)]
class A {
AMethod() { }
[Friend(C)]
ACMethod() { }
}
class B {
BMethod() { A.AMethod() }
}
class C {
CMethod() { A.ACMethod() }
}
У випадку з моїм попереднім прикладом, можливо, є щось на кшталт наступного (можна аргументувати семантику, але я просто намагаюся донести цю думку):
class BasePage {
[Friend(BaseControl.ReportError(string)]
protected void ReportError(string str) { }
}
class BaseControl {
protected void ReportError(string str) {
MyBasePage bp = Page as MyBasePage;
bp.ReportError(str);
}
}
Як я бачу, концепція друга не має для цього більшого ризику, ніж оприлюднення речей або створення публічних методів чи властивостей для доступу до членів. Якщо що-небудь друг дозволяє інший рівень деталізації в доступності даних і дозволяє вам звузити цю доступність, а не розширити її внутрішніми або загальнодоступними.