Часть 1. Основы ООП Наследование и полиморфизм.
Пример: кодирование На вход подаются данные из файла, памяти или локальной сети. Данные представлены потоком байт и кодируются одним из алгоритмов. На выходе – файл, память или сеть. encodeBase64MemoryToFile encodeLzFileToNet encodeRlaNetToMemory
Выделение абстракций Отделим чтение данных от кодирования. Получим читателя – Reader. Отделим запись данных от кодирования. Получим писателя – Writer. Остается алгоритм кодирования и декодирования в чистом виде. ReaderWriterАлгоритм
Определение Абстракция – это модель семейства объектов, в которой фиксируются существенные свойства семейства (операции и связи с другими абстракциями), и игнорируются другие его свойства, признаваемые «частными», несущественными.
Реализация абстракций Три читателя: FileReader, NetworkReader, MemoryReader. Три писателя: FileWriter, NetworkWriter, MemoryWriter. Три алгоритма: LzAlgorithm, Base64Algorithm, RlaAlgorithm. «Что умеет делать каждый?» – важно. «Как он это делает?» – не важно.
Преимущества Любые читатель, писатель и алгоритм могут быть соединены в нужной связке. Ошибка в одной из реализаций абстракции локализует исправления. Появление новой разновидности не требует больших затрат. Работу каждой из реализаций можно протестировать изолированно.
Пример: кодирование public interface Reader { // Java byte readByte(); boolean hasMoreBytes(); } // Reader.java public interface Writer { void writeByte(byte value); } // Writer.java public interface EncodingAlgorithm { void encode(Reader Source, Writer Destination); void decode(Reader Source, Writer Destination); } // EncodingAlgorithm.java
Интерфейс Интерфейс – это объявление операций, которые можно произвести с абстракцией. Интерфейс – это основа контракта между двумя абстракциями. Интерфейс не определяет реализацию. Интерфейс определяет новый тип данных.
Пример: кодирование public class FileReader implements Reader { // Java void read() {... } boolean hasMoreBytes() {... } } // см. MemoryReader.java Теперь FileReader можно использовать вместо Reader.
Пример: кодирование public class PlainEncodingAlgorithm implements EncodingAlgorithm { public void encode(Reader Source, Writer Destination) { // Java while ( Source.hasMoreBytes() ) { byte b = Source.readByte(); Destination.writeByte ( b ); } public void decode(Reader Source, Writer Destination) { encode ( Source, Destination ); } } // PlainEncodingAlgorithm.java
Полиморфизм Классы, реализующие интерфейс, совместимы с ним по присваиванию. Алгоритм кодирования может работать с читателями и писателями любой формы (т. е. он полиморфен). В том месте, где требуется интерфейс, можно использовать любую форму его реализации (т. е. любой класс, реализующий этот интерфейс).
Абстрактный класс public class Reader // Java { public abstract bool HasMoreBytes(); public abstract byte readByte(); byte[] readBytes(int count) { byte[] buffer = new byte[count]; for(int i=0; i
Наследование public class FileReader extends Reader { // Java void read() {... } boolean hasMoreBytes() {... } Теперь FileReader можно использовать вместо Reader.
Переопределение методов public class NetReader extends Reader { // Java byte[] readBytes(int count) {... } Если не нравится, как реализован метод, можно переопределить его в наследнике.
Особенности языка C++ public: virtual vector readBytes(int count) {... } В C++ можно переопределять только виртуальные методы ( virtual ). В Java запретить переопределение можно пометив метод ключевым словом final.
Особенности C++ class FileReaderWriter: public Reader, Writer {... } В C++ разрешено множественное наследование. В Java можно наследовать от 1 класса.
Особенности C++ class Reader { public: virtual char readByte() = 0; } В C++ отсутствуют интерфейсы. Их заменяют чисто абстрактные классы.
Дизайн по контракту Интерфейс – это часть контракта. В контракте не описан способ реализации (выполн.) контракта (см. инвариант). В контракте описан способ использован., подходящий для всех реализаций. Бертран Майер «Объектно- ориентированное конструирование программного обеспечения» (EIFEL).