Alguns sugeriram que as coisas podem ficar fora de controle usando o amigo. Eu concordo, mas isso não diminui sua utilidade. Não tenho certeza de que um amigo necessariamente prejudique o paradigma OO mais do que tornar todos os membros de sua classe públicos. Certamente o idioma permitirá que você publique todos os seus membros, mas é um programador disciplinado que evita esse tipo de padrão de design. Da mesma forma, um programador disciplinado reservaria o uso de friend para casos específicos em que isso faz sentido. Sinto exposições internas demais em alguns casos. Por que expor uma classe ou método a tudo na montagem?
Eu tenho uma página ASP.NET que herda minha própria página base, que por sua vez herda System.Web.UI.Page. Nesta página, tenho um código que lida com o relatório de erros do usuário final para o aplicativo em um método protegido
ReportError("Uh Oh!");
Agora, eu tenho um controle de usuário que está contido na página. Desejo que o controle do usuário possa chamar os métodos de relatório de erros na página.
MyBasePage bp = Page as MyBasePage;
bp.ReportError("Uh Oh");
Não é possível fazer isso se o método ReportError estiver protegido. Eu posso torná-lo interno, mas está exposto a qualquer código no assembly. Eu só quero que ele seja exposto aos elementos da interface do usuário que fazem parte da página atual (incluindo controles filho). Mais especificamente, quero que minha classe de controle base defina exatamente os mesmos métodos de relatório de erros e chame simplesmente métodos na página base.
protected void ReportError(string str) {
MyBasePage bp = Page as MyBasePage;
bp.ReportError(str);
}
Acredito que algo como amigo poderia ser útil e implementado na linguagem sem tornar a linguagem menos "OO", talvez como atributos, para que você possa ter classes ou métodos amigos de classes ou métodos específicos, permitindo que o desenvolvedor forneça muito acesso específico. Talvez algo como ... (pseudo código)
[Friend(B)]
class A {
AMethod() { }
[Friend(C)]
ACMethod() { }
}
class B {
BMethod() { A.AMethod() }
}
class C {
CMethod() { A.ACMethod() }
}
No caso do meu exemplo anterior, talvez tenha algo como o seguinte (pode-se argumentar semântica, mas estou apenas tentando transmitir a ideia):
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);
}
}
A meu ver, o conceito de amigo não tem mais riscos do que tornar públicas as coisas ou criar métodos ou propriedades públicas para acessar os membros. Se alguma coisa amiga permitir outro nível de granularidade na acessibilidade dos dados e permitir que você restrinja essa acessibilidade em vez de ampliá-la com interna ou pública.