Проблема
Скажем, я пытаюсь моделировать мобильный телефон как комбинацию обычного телефона и КПК. Это своего рода сценарий множественного наследования (сотовый телефон - это телефон, и это КПК). Поскольку С# не поддерживает множественное наследование, это в значительной степени требует некоторой композиции. Кроме того, позвольте сказать, что у меня есть другие причины, чтобы поддержать композицию в любом случае.
Я всегда задаюсь вопросом: есть ли какие-либо инструменты, которые автоматически генерируют весь неизбежный сквозной код?
Позвольте мне изложить мой пример с каким-то фактическим кодом:
Интерфейсы:
public interface IPhone
{
public void MakeCall(int phoneNumber);
public void AnswerCall();
public void HangUp();
}
public interface IPda
{
public void SendEmail(string[] recipientList, string subject, string message);
public int LookUpContactPhoneNumber(string contactName);
public void SyncWithComputer();
}
Реализации:
public class Phone : IPhone
{
public void MakeCall(int phoneNumber) { // implementation }
public void AnswerCall() { // implementation }
public void HangUp() { // implementation }
}
public class Pda : IPda
{
public void SendEmail(string[] recipientList, string subject, string message) { // implementation }
public int LookUpContactPhoneNumber(string contactName) { // implementation }
public void SyncWithComputer() { // implementation }
}
Класс CellPhone
public class CellPhone : IPhone, IPda
{
private IPhone _phone;
private IPda _pda;
public CellPhone(IPhone phone, IPda pda)
{
_phone = phone;
_pda = pda;
}
public void MakeCall(int phoneNumber)
{
_phone.MakeCall(phoneNumber);
}
public void AnswerCall()
{
_phone.AnswerCall();
}
public void HangUp()
{
_phone.HangUp();
}
public void SendEmail(string[] recipientList, string subject, string message)
{
_pda.SendEmail(recipientList, subject, message);
}
public int LookUpContactPhoneNumber(string contactName)
{
return _pda.LookUpContactPhoneNumber(contactName);
}
public void SyncWithComputer()
{
_pda.SyncWithComputer();
}
}
Написание класса CellPhone является утомительным и подверженным ошибкам:
Весь этот класс действительно действует как канал для классов Phone
и Pda
. На самом деле нет никаких оснований для того, чтобы человеческие усилия требовались для ввода всех этих сквозных утверждений (например, _phone.MakeCall(phoneNumber);
). Он просто раскрывает открытый интерфейс полей нескольких членов.
Вопросы
-
Есть ли инструмент (желательно свободный:)), который спасет меня от ошибок, связанных с ошибкой написания сквозных методов? Я знаю, что я могу автоматически генерировать заглушки с помощью VS, но это только помогает мне на полпути.
-
Можете ли вы оценить целесообразность и желательность такой функции? Стоит ли предлагать Microsoft добавить такой тип генерации кода? Не могли бы вы его перенести, если бы я это сделал? Если нет, какие у вас есть возражения?
Edit
Кажется, что все говорят одно и то же: почему бы мне просто не сделать _phone
и _pda
в общедоступные свойства? Мое возражение против этого заключается в том, что оно нарушает "принцип наименьшего знания". Клиент моего класса CellPhone
должен просто делать то, что делает сотовый телефон, ему не нужно иметь дело с выяснением, какие функции являются Phone
функциями и которые являются Pda
функциями. Это создает дополнительные зависимости и делает возможности интерфейса CellPhone менее очевидными.
Кроме того, не сосредотачивайтесь только на этом примере. Что, если я пишу адаптер? Он может содержать несколько интерфейсных элементов, которые являются просто сквозными, но также могут содержать некоторые уникальные элементы с уникальной реализацией. Я считаю, что есть много случаев, когда сквозной код - это хорошо, мне просто не нравится писать его.