Я прочитал статью Роберта Мартина о принципе разделения интерфейсов здесь . В конце статьи, решая проблему с архитектурой пользовательского интерфейса банкомата, он заявил:
Учтите также, что каждая отдельная транзакция, которую может выполнять банкомат, заключена как производная от класса Transaction. Таким образом, у нас могут быть такие классы, как DepositTransaction
, WithdrawlTransaction
, TransferTransaction
, et c. Каждый из этих объектов отправляет сообщение на UI
. Например, объект DepositTransaction
вызывает функцию-член RequestDepositAmount
класса UI
. В то время как объект TransferTransaction
вызывает функцию-член RequestTransferAmount
для UI
. Это соответствует диаграмме на Рисунке 5.
Обратите внимание, что это точно та ситуация, которую провайдер советует нам избегать. Каждая транзакция использует часть UI
, которую не использует ни один другой объект. Это создает возможность того, что изменения в одной из производных от Transaction
вызовут соответствующее изменение на UI
, тем самым повлияв на все другие производные от Transaction и любой другой класс, который зависит от интерфейса UI
.
Итак, мы имеем следующую ситуацию: если одна из производных Transaction
изменяется, то UI
изменяется и любой другой класс, использующий UI
, также изменяется.
Затем эта проблема решается следующими изменениями:
Этого неудачного сцепления можно избежать, разделив интерфейс пользовательского интерфейса на отдельные абстрактные базовые классы, такие как DepositUI
, WithdrawUI
и TransferUI
. Эти абстрактные базовые классы затем могут быть многократно унаследованы в последний абстрактный класс UI
. На рисунке 6 и в листинге 6 показана эта модель.
Но затем Роберт Мартин заявляет, что:
Это правда, что всякий раз, когда создается новая производная от класса Transaction, Для абстрактного UI-класса потребуется соответствующий базовый класс. Таким образом, UI-класс и все его производные должны измениться. Однако эти классы не получили широкого распространения. В самом деле, они, вероятно, используются только основным или каким-либо другим процессом, загружающим систему и создающим конкретный экземпляр пользовательского интерфейса. Таким образом, влияние добавления новых базовых классов пользовательского интерфейса сдерживается.
И вот вопрос: как это возможно, что UI
изменился, но никакие другие классы тоже не изменились? В конце концов, если какой-то TransactionX
использует XUI
, а XUI
является суперклассом UI
и UI
изменяется (из-за какого-то ZUI
), то (насколько мне известно) компилятор также необходимо перекомпилировать все классы, которые используют XUI
, потому что vtable (в терминах C ++) или, возможно, некоторые базовые адреса функций были изменены путем изменения UI
. Может ли кто-нибудь очистить его для меня?