Советы и лайфхаки

Абстракция программирование – Абстракция данных — Википедия

Содержание

python — Что означает абстракция при программировании?

Абстракция является основной концепцией во всех компьютерных науках. Без абстракции мы все равно будем программировать в машинный код или, хуже того, не иметь компьютеров в первую очередь. Так ИМХО, что действительно хороший вопрос.

Что такое абстракция

Абстрактное что-то означает давать имена вещам, так что имя фиксирует ядро ​​того, что делает функция или целая программа.

Один пример приведен в книге, на которую вы ссылаетесь, где говорится

Предположим, что мы работали с черепахами, и нам нужна общая операция рисовать квадраты. «Нарисуйте квадрат» — это абстракция или ментальный кусок, из нескольких меньших шагов. Поэтому давайте напишем функцию для захвата шаблон этого «строительного блока»:

Забудьте о черепах на мгновение и просто подумайте о рисовании квадрата. Если я скажу вам нарисовать квадрат (на бумаге), вы сразу же узнаете, что делать:

  • нарисуйте квадрат = > нарисуйте прямоугольник со всеми сторонами одинаковой длины.

Вы можете сделать это без дальнейших вопросов, потому что вы знаете наизусть, что такое квадрат, без чего я говорю вам шаг за шагом. Здесь слово square является абстракцией «нарисуйте прямоугольник со всеми сторонами одной длины».

Абстракции работают глубоко

Но подождите, откуда вы знаете, что такое прямоугольник? Ну, это еще одна абстракция для следующего:

  • rectangle = > нарисуйте две прямые, параллельные друг другу, одной длины, а затем добавьте еще две параллельные линии, перпендикулярные двум другим линиям, снова одной длины, но, возможно, различной длины, чем первые два.

Конечно, он продолжается, и он-лайн, параллельный, перпендикулярный, соединяющий все абстракции хорошо известных понятий.

Теперь представьте, что каждый раз, когда вы хотите, чтобы прямоугольник или квадрат рисовался, вы должны дать полное определение прямоугольника или объяснить строки, параллельные линии, перпендикулярные линии и соединительные линии. Это займет слишком много времени сделайте это.

Действительная сила абстракции

Это первая сила абстракций: они делают разговоры и делают все намного проще.

Вторая сила абстракций исходит из приятного свойства композиции: как только вы определили абстракции, вы можете создать две или более абстракции, чтобы сформировать новую большую абстракцию: скажем, вы устали рисовать квадраты, но вы действительно хотите нарисовать дом. Предположим, что мы уже определили треугольник, поэтому мы можем определить:

  • house = > нарисуйте квадрат с треугольником над ним

Затем вы хотите деревню:

  • деревня = > нарисовать несколько домов рядом друг с другом.

О, подождите, мы хотим город — и у нас есть новая концепция улицы:

  • city = > привлечь много деревень близко друг к другу, заполнить пустые пространства большим количеством домов, но оставить место для улиц.
  • street = > (определение улицы)

и т.д.

Как это все относится к программированию?

Если при планировании вашей программы (процесса, известного как анализ и дизайн) вы обнаружите хорошие абстракции к проблеме, которую вы пытаетесь решить, ваши программы становятся короче, поэтому легче писать и, возможно, более важно — проще читать. Способ сделать это — попытаться понять основные концепции, которые определяют ваши проблемы — как в (упрощенном) примере рисования дома, это были квадраты и треугольники, чтобы рисовать деревню, это были дома.

В программировании мы определяем абстракции как функции (и некоторые другие конструкции, такие как классы и модули, но теперь будем фокусироваться на функциях). Функция по существу называет набор отдельных операторов, поэтому функция по существу является абстракцией — подробности см. В примерах в вашей книге.

Красота всего этого

В программировании абстракции могут создавать или нарушать производительность. Поэтому часто часто используемые функции собираются в библиотеки, которые могут быть повторно использованы другими. Это означает, что вам не нужно беспокоиться о деталях, вам нужно только понять, как использовать готовые абстракции. Очевидно, что это должно облегчить вам задачу, поэтому вы можете работать быстрее и, следовательно, быть более продуктивным:

Пример:

Представьте, что есть графическая библиотека под названием «nicepic», которая содержит предопределенные функции для всех абстракций, рассмотренных выше: прямоугольники, квадраты, треугольники, дом, деревня.

Предположим, вы хотите создать программу, основанную на вышеуказанных абстракциях, которая красит красивую картину дома, все, что вам нужно написать, это:

import nicepic
draw_house()

Итак, просто две строки кода, чтобы получить что-то более сложное. Разве это не замечательно?

Надеюсь, что это поможет.

qaru.site

Принципы ООП Java / Объектно-ориентированное программирование

Java является объектно-ориентированным языком. Это означает, что писать программы на Java нужно с применением объектно-ориентированного стиля. И стиль этот основан на использовании в программе объектов и классов. Попробуем с помощью примеров разобраться, что такое классы и объекты, а также с тем, как применять на практике основные принципы ООП: абстракцию, наследование, полиморфизм и инкапсуляцию.

Что такое объект?

Мир, в котором мы живем, состоит из объектов. Если мы посмотрим вокруг, то увидим, что нас окружают дома, деревья, автомобили, мебель, посуда, компьютеры. Все эти предметы являются объектами, и каждый из них обладает набором определенных характеристик, поведением и назначением. Мы привыкли к объектам, и мы их используем всегда для вполне конкретных целей. Например, если нам необходимо доехать до работы, мы пользуемся автомобилем, если захотим поесть – посудой, а если отдохнуть – нам понадобится удобный диван. Человек привык мыслить объектно для решения задач в повседневной жизни. Это послужило одной из причин использования объектов в программировании, а такой подход к созданию программ назвали объектно-ориентированным. Приведём пример. Представьте, что вы разработали новую модель телефона и хотите наладить её серийное производство. Как разработчик телефона, вы знаете для чего он нужен, как он будет функционировать, и из каких деталей он будет состоять (корпус, микрофон, динамик, провода, кнопки и т.д.). При этом только вы знаете, как соединить эти детали. Однако вы не планируете выпускать телефоны лично, для этого у вас есть целый штат работников. Чтобы вам не пришлось каждый раз объяснять, как соединить детали телефона, и чтобы все телефоны при производстве получались одинаковыми, прежде чем начать их выпуск, вам понадобиться сделать чертеж в виде описания устройства телефона.
В ООП такое описание, чертеж, схема или шаблон называется классом, из которого при выполнении программы создается объект.
Класс — это описание еще не созданного объекта, как бы общий шаблон, состоящий из полей, методов и конструктора, а объект – экземпляр класса, созданный на основе этого описания.

Абстракция

Давайте теперь подумаем, как нам перейти от объекта из реального мира к объекту в программе на примере телефона. История этого средства связи превышает 100 лет и современный телефон, в отличие от своего предшественника из 19 века, представляет собой куда более сложное устройство. Когда мы пользуемся телефоном, то не задумываемся о его устройстве и процессах, происходящих внутри него. Мы просто используем функции, предоставленные разработчиками телефона — кнопки или сенсорный экран для выбора номера и совершения вызовов. Одним из первых интерфейсов телефона была рукоятка, которую нужно было вращать, чтобы сделать вызов. Разумеется, это было не очень удобно. Тем не менее, свою функцию рукоять исправно выполняла. Если посмотреть на самый современный и на самый первый телефон, можно сразу выделить самые важные детали, которые важны и для устройства конца 19-го века, и для суперсовременного смартфона. Это совершение вызова (набор номера) и приём вызова. По сути это то, что делает телефон телефоном, а не чем-то другим. Сейчас мы применили принцип в ООП — выделение наиболее важных характеристик и информации об объекте.
Этот принцип называется абстракцией.
Абстракцию в ООП можно также определить, как способ представления элементов задачи из реального мира в виде объектов в программе. Абстракция всегда связана с обобщением некоторой информации о свойствах предметов или объектов, поэтому главное — это отделить значимую информацию от незначимой в контексте решаемой задачи. При этом уровней абстракции может быть несколько. Попробуем применить принцип абстракции к нашим телефонам. Для начала выделим наиболее распространённые типы телефонов от самых первых и до наших дней. Например, их можно представить в виде диаграммы, приведенной на рисунке 1.
Теперь с помощью абстракции мы можем выделить в этой иерархии объектов общую информацию: общий абстрактный тип объектов — телефон, общую характеристику телефона — год его создания, и общий интерфейс — все телефоны способны принимать и посылать вызовы. Вот как это выглядит на Java:
public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outputNumber);
    public abstract void ring (int inputNumber);
}
На основании этого абстрактного класса мы сможем создавать в программе новые типы телефонов с использованием других базовых принципов ООП Java, которые рассмотрим ниже.

Инкапсуляция

С помощью
абстракции
мы выделяем общее для всех объектов. Однако каждая модель телефона — индивидуальна и чем-то отличается от других. Как же нам в программе провести границы и обозначить эту индивидуальность? Как сделать так, чтоб никто из пользователей случайно или преднамеренно не смог сломать наш телефон, или попытаться переделать одну модель в другую? Для мира реальных объектов ответ очевиден: нужно поместить все детали в корпус телефона. Ведь если этого не сделать и оставить все внутренности телефона и провода, соединяющие их снаружи, обязательно найдется любознательный экспериментатор, который захочет “улучшить” работу нашего телефона. Для исключения подобного вмешательства в конструкцию и работу объекта в ООП используют принцип инкапсуляции – еще один базовый принцип ООП, при котором атрибуты и поведение объекта объединяются в одном классе, внутренняя реализация объекта скрывается от пользователя, а для работы с объектом предоставляется открытый интерфейс. Задача программиста — определить, какие атрибуты и методы будут доступны для открытого доступа, а какие являются внутренней реализацией объекта и должны быть недоступны для изменений.

Инкапсуляция и управление доступом

Допустим, при производстве на тыльной стороне телефона гравируется информация о нем: год его выпуска или логотип компании производителя. Эта информация вполне конкретно характеризует данную модель — его состояние. Можно сказать, разработчик телефона позаботился о неизменности этой информации — вряд ли кому-то придет в голову удалять гравировку. В мире Java состояние будущих объектов описывается в классе с помощью полей, а их поведение – с помощью методов. Возможность же изменения состояния и поведения осуществляется с помощью модификаторов доступа к полям и методам –
private, protected, public
, а также default (доступ по умолчанию). Например, мы решили, что год создания, название производителя телефона и один из методов относятся к внутренней реализации класса и не подлежат изменению другими объектами в программе. С помощью кода класс можно описать так:
public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    
    
}
public void call() {
    openConnection();
    System.out.println("Вызываю номер");
}

public void ring() {
    System.out.println("Дзынь-дзынь");
}

 }
Модификатор private делает доступными поля и методы класса только внутри данного класса. Это означает, что получить доступ к private полям из вне невозможно, как и нет возможности вызвать private методы. Сокрытие доступа к методу openConnection, оставляет нам также возможность к свободному изменению внутренней реализации этого метода, так как этот метод гарантированно не используется другими объектами и не нарушит их работу. Для работы с нашим объектом мы оставляем открытыми методы call и ring с помощью модификатора public. Предоставление открытых методов для работы с объектом также является частью механизма инкапсуляции, тат как если полностью закрыть доступ к объекту – он станет бесполезным.

Наследование

Давайте посмотрим еще раз на диаграмму телефонов. Можно заметить, что она представляет собой иерархию, в которой модель, расположенная ниже обладает всеми признаками моделей, расположенных выше по ветке, плюс своими собственными. Например, смартфон, использует сотовую сеть для связи (обладает свойствами сотового телефона), является беспроводным и переносным (обладает свойствами беспроводного телефона) и может принимать и делать вызовы (свойствами телефона). В этом случае мы можем говорить о наследовании свойств объекта. В программировании наследование заключается в использовании уже существующих классов для описания новых. Рассмотрим пример создания класса смартфон с помощью наследования. Все беспроводные телефоны работают от аккумуляторных батарей, которые имеют определенный ресурс работы в часах. Поэтому добавим это свойство в класс беспроводных телефонов:
public abstract class WirelessPhone extends AbstractPhone {

    private int hour;

    public WirelessPhone(int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
Сотовые телефоны наследуют свойства беспроводного телефона, мы также добавили в этот класс реализацию методов call и ring:
public class CellPhone extends WirelessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("Вызываю номер " + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Вам звонит абонент " + inputNumber);
    }
}
И, наконец, класс смартфон, который в отличие от классических сотовых телефонов имеет полноценную операционную систему. В смартфон можно добавлять новые программы, поддерживаемые данной операционной системой, расширяя, таким образом, его функциональность. С помощью кода класс можно описать так:
public class Smartphone extends CellPhone {

    private String operationSystem;

    public Smartphone(int year, int hour, String operationSystem) {
        super(year, hour);
        this.operationSystem = operationSystem;
    }
public void install(String program){
    System.out.println("Устанавливаю " + program + "для" + operationSystem);
}

}
Как видите, для описания класса Smartphone мы создали совсем немного нового кода, но получили новый класс с новой функциональностью. Использование этого принципа ООП java позволяет значительно уменьшить объем кода, а значит, и облегчить работу программисту.

Полиморфизм

Если мы посмотрим на все модели телефонов, то, несмотря на различия во внешнем облике и устройстве моделей, мы можем выделить у них некое общее поведение – все они могут принимать и совершать звонки и имеют достаточно понятный и простой набор кнопок управления. Применяя известный нам уже один из основных принципов ООП абстракцию в терминах программирования можно сказать, что объект телефон имеет один общий интерфейс. Поэтому пользователи телефонов могут вполне комфортно пользоваться различными моделями, используя одни и те же кнопки управления (механические или сенсорные), не вдаваясь в технические тонкости устройства. Так, вы постоянно пользуетесь сотовым телефоном, и без труда сможете совершить звонок с его стационарного собрата. Принцип в ООП, когда программа может использовать объекты с одинаковым интерфейсом без информации о внутреннем устройстве объекта, называется полиморфизмом. Давайте представим, что нам в программе нужно описать пользователя, который может пользоваться любыми моделями телефона, чтобы позвонить другому пользователю. Вот как можно это сделать:
public class User {
    private String name;

    public User(String name) {
        this.name = name;
            }

    public void callAnotherUser(int number, AbstractPhone phone){

        phone.call(number);
    }
}
 }
Теперь опишем различные модели телефонов. Одна из первых моделей телефонов:
public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outputNumber) {
        System.out.println("Вращайте ручку");
        System.out.println("Сообщите номер абонента, сэр");
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Телефон звонит");
    }
}
Обычный стационарный телефон:
public class Phone extends AbstractPhone {

    public Phone(int year) {
        super(year);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("Вызываю номер" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Телефон звонит");
    }
}
И, наконец, крутой видеотелефон:
public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outputNumber) {
        System.out.println("Подключаю видеоканал для абонента " + outputNumber );
    }
    @Override
    public void ring(int inputNumber) {
        System.out.println("У вас входящий видеовызов..." + inputNumber);
    }
  }
Создадим объекты в методе main() и протестируем метод callAnotherUser:
AbstractPhone phone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User("Андрей");
user.callAnotherUser(224466,firstPhone);


user.callAnotherUser(224466,phone);

user.callAnotherUser(224466,videoPhone);
Используя вызов одного и того же метода объекта user, мы получили различные результаты. Выбор конкретной реализации метода call внутри метода callAnotherUser производился динамически на основании конкретного типа вызывающего его объекта в процессе выполнения программы. В этом и заключается основное преимущество полиморфизма – выбор реализации в процессе выполнения программы. В примерах классов телефонов, приведенных выше, мы использовали переопределение методов – прием, при котором изменяется реализация метода, определенная в базовом классе, без изменения сигнатуры метода. По сути это является заменой метода, и именно новый метод, определенный в подклассе, вызывается при выполнении программы. Обычно, при переопределении метода, используется аннотация @Override, которая подсказывает компилятору о необходимости проверить сигнатуры переопределяемого и переопределяющего методов. В итоге, чтобы стиль вашей программы соответствовал концепции ООП и принципам ООП java следуйте следующим советам:
  • выделяйте главные характеристики объекта;
  • выделяйте общие свойства и поведение и используйте наследование при создании объектов;
  • используйте абстрактные типы для описания объектов;
  • старайтесь всегда скрывать методы и поля, относящиеся к внутренней реализации класса.

javarush.ru

Абстрактно ориентированный программист / Хабр

Начну с истории о программистах, которую мне приходилось слышать неоднократно.
Я попросил Джо написать простенькую программу, которая делает &ltxyz&gt. Работы там было на несколько часов, в худшем случае на день. Ему понадобилось несколько дней, за который он написал гораздо более сложный фреймворк, чем требовалось. Почему он снова так намудрил?

Возможно, дело в том, что Джо – Абстрактно ориентированный программист (АОП) .
Вот несколько шаблонных фраз (snowclones)

Если вы часто усложняете (over-engineer) свои программы, возможно вы АОП.

Если вы проводите больше времени, размышляя о завтрашних проблемах, чем о текущих, возможно, вы АОП>.

Если вам нравится искать глубинные взаимосвязи, ощущать приятную дрожь от бессознательных озарений или рассуждать аналогиями, возможно, вы АОП.

Необходимость абстракций

Разработка программного обеспечения – одно из немногих занятий в котором постоянно приходится иметь дело с абстракциями. Языки программирования, типы данных, графические представления, потоки управления и т.д. являются абстракциями реального мира, абстракциями аппаратного обеспечения и часто абстракциями абстракций.

Резкий рост производительности процессоров (в соответствии с законом Мура) рождает потребность в абстракциях. Я начинал программировать на компьютерах с процессорами, счет транзисторов в которых шел на сотни. У Motorolla 6800 было 4100 транзисторов и тактовая частота 1-2 мегагерца. Zilog Z80 имел 8500 транзисторов и частоту 2-8 МГц. Понимание работы регистров процессора, прерываний и других в каком-то смысле физических процессов очень сильно помогало, когда требовалось заставить эти компьютеры делать что-нибудь действительно полезное.

Сейчас в массовое производство запущены процессоры с миллиардом или около того транзисторов. Например Intel Core i7 содержит около миллиарда транзисторов, и имеет тактовую частоту 2-3.5 ГГц.

Это, примерно, в миллиард раз превосходит вычислительную мощность компьютеров тридцатилетней давности. Человек же так заметно эволюционировать не сумел. Возникла необходимость эффективно использовать прирост мощности процессоров. Тут-то и появились компиляторы, виртуальные машины, сложные интерфейсы, всевозможные оптимизаторы, высокоуровневые языки программирования и другие инструменты. Между аппаратным обеспечением и современными программами лежит множество слоев абстракции. И, конечно же, они необходимы.

Таким образом, нет ничего удивительного в том, что программирование привлекает людей со склонностью к абстрактному мышлению… и, возможно, человек с абстрактным мышлением имеет больше шансов получать удовольствие от работы и добиваться успехов в этой области.

Но, рассуждая подобным образом, очень легко забыть, что не всем людям свойственно абстрактное мышление. Можно даже сделать вывод, что все программисты абстрактно ориентированны или ошибочно заключить, что абстрактное мышление является наилучшим вариантом для них.

Абстрактное мышление

Для начала рассмотрим определения
Абстрактный (прилагательное)
  • отвлеченный, не связанный с непосредственным восприятием реального мира (т.е. фактами)
  • не прикладной или практический, теоретический

Абстракция (существительное)
  • процесс формулирования обобщенных идей или концепций посредством извлечения общих свойств или закономерностей из определенного набора примеров

Абстракции – это по определению упрощение информации, которое достигается рассмотрением большого количества примеров и сжатием их в общий шаблон.

Для некоторых людей естественно абстрактное мышление, в то же время другие предпочитают конкретные факты. Абстрактно выражаясь, речь идет о способе, которым люди обрабатывают информацию.

Рассмотрим индикатор типов личности Майерс-Бриггс, который широко используется в бизнесе. Индикатор позволяет определить четыре типа личности, которые подразделяются на основанные на интуиции и здравом смысле (N и S, если использовать обозначения типологии) – соответственно на абстрактное и конкретное мышление. (Существуют другие психологические исследования с похожим разделением типов личности)

Перечислим некоторые особенности, проявляющиеся при абстрактном и конкретном мышлении.

Ввиду того, что многие люди подстраивают свое поведение под обстоятельства, вы также можете трактовать приведенную информацию как абстрактное или конкретное текущее состояние сознания, хотя считается, что каждый человек имеет доминирующую склонность.

Признаки абстрактного/интуитивного мышления

  • Мысли и идеи
  • Чтение между строк
  • Жизнь будущим – бо́льшая заинтересованность проявляется по отношению к будущим возможностям
  • Лучше запоминаются шаблоны, контекст и взаимосвязи
  • Комфортно себя чувствуешь, работая с неопределенными размытыми данными, когда приходится угадывать их смысл
  • Большее доверие проявляется к абстрактной или теоретической информации, взаимосвязям и шаблонам

Признаки конкретного мышления

  • Реальные объекты и вещи
  • Чтение самих строк
  • Фокусировка на «здесь и сейчас»
  • В памяти хранится большое количество деталей и фактов
  • Предпочтение отдается четкой и точной информации, не нравится выдвигать догадки, когда нет четких фактов
  • Предпочтение отдается информации в настоящем времени, которую можно ощутить одним из пяти чувств
  • Недоверие к догадкам, которые, кажется, появились из неоткуда.

Вернемся к Джо

Вернемся к истории о Джо, с которой начиналась данная статья, где он усложнял (over-engineer) код. Для абстрактно ориентированного программиста тут все логично
  • Сегодня мы имеем проблему X
  • X – это отдельный пример более общего класса задач, который также включает Y и Z
  • Чтобы проблемы Y и Z не случились в будущем, я должен написать код, который решает X, Y и Z

Однако, когда во время общения с Джо мы попросили его решить только задачу X, в то время как он знал, что в будущем Y и Z неминуемы, мы обрекли его на расстройство из-за некачественно выполненной работы или даже уверенность, что в будущем его сделают крайним.

Здесь на первый план выходит текущая ситуация. Умение думать наперед может сделать из вас героя. Также умение думать наперед с легкостью превратит вас в обузу. Концентрируясь же исключительно на сиюминутных проблемах, вы станете героем… или обузой.

Весь фокус в понимании, какой подход будет уместным в той или иной ситуации, проще говоря, адаптируйтесь.

Также очень важно согласовывать выбранную стратегию с коллегами, другими словами, общайтесь.

Приведу некоторые отзывы, которые я слышал об абстрактно ориентированных программистах…

Позитив

  • Она берется за плохо поставленные задачи и прекрасно с ними справляется
  • Он глубоко продумывает проблему, в результате предлагая элегантные решения
  • Она постоянно пробует разные приемы в поисках лучшего подхода
  • Команда (АОП) неожиданно выдвинула ряд прекрасных идей

Негатив

  • Он постоянно сражается с будущими проблемами, я не могу заставить его сделать быструю правку, когда это необходимо
  • Она часто сильно усложняет (over-engineer) свой код. Иногда мне нужен просто быстрый хак.
  • Он постоянно пытается переписать всю нашу кодовую базу. Унаследованный код работает – просто оставь его в покое.
  • Почему она не следует общему плану работ
  • Совещания нашей команды (АОП) постоянно уходят от насущных проблем. Конечно, обсуждения получаются интересными, но нам нужно сконцентрироваться на решаемой задаче.

… и то же самое про конкретно ориентированных программистов (КОП)

Позитив

  • Он долго не рассуждает. Просто берет задачу и решает ее.
  • Она в курсе наших технологических процессов и следует им
  • Он демонстрирует здравый смысл
  • Эта команда (КОП) постоянно занимается той задачей, которую они могут и должны делать.

Негатив

  • Его код решает узкий круг задач. Этого достаточно, чтобы пройти тесты, но мало для реального использования
  • Ее код негибок и труден в сопровождении. Каждый раз при добавлении новой функции мы вынуждены все переписывать заново.
  • Он ничего не видит за пределами текущей задачи. Его код не протянет долго.
Мини тест

Список А. Сколько из приведенных в нем пунктов описывают вас наилучшим образом? (Отвечайте не задумываясь)
  1. Вас больше интересует идея в общем, чем тонкости ее реализации
  2. Вы часто задумываетесь о судьбе человечества
  3. Вы с легкостью выделяете общие закономерности из конкретных примеров
  4. Вы часто рассуждаете о сложности жизни
  5. Вы считаете, что практически все поддается анализу
  6. Вы с легкостью понимаете новые теоретические принципы
  7. Вы часто проводите время за размышлениями, как сделать что-либо лучше
  8. Вы с легкостью просчитываете разные пути, по которым может пойти развитие ситуации

Список Б. Сколько из приведенных в нем пунктов описывают вас наилучшим образом?
  1. Вам скучно читать теоретические книги
  2. Вы предпочитаете опираться на свой опыт, а не на теоретические альтернативы
  3. Для вас важно пробовать сделать что-то своими руками
  4. Анализируя ситуацию, вы основное внимание уделяете текущему ее состоянию, а не возможным последствиям
  5. Как правило, текущие занятия волнуют вас больше, чем планы на будущее

Если вы согласились с бо́льшим числом пунктов из списка А, чем Б, вы, должно быть, абстрактно ориентированы. И наоборот, если преобладали утверждения из списка Б, вы относитесь к конкретному типу личности.

[Сразу хочу оговориться. Во-первых, тип личности – это не судьба. Очень часто жизнь требует от нас адаптировать свое поведение ради семьи, работы, друзей и т.п. Во-вторых, вполне может оказаться, что в зависимости от вашей текущей ситуации вы можете отвечать на одни и те же вопросы по-разному. В-третьих, речь идет об описании вашего доминирующего стиля мышления – не нужно воспринимать это как призыв к действию.]

Адаптируем мышление

Несколько лет назад я услышал хорошую аналогию. Вы можете быть правшой или левшой. Большинство людей используют одну руку в качестве основной, некоторые свободно владеют обеими. Но только из того, что кто-то чаще пользуется правой рукой, не следует, что ему вообще не нужна левая. Кроме того, некоторые задачи требуют использования определенной руки – попробуйте воспользоваться ножницами для правшей левой рукой или вести машину, переключая скорости не той рукой, которая предполагалась производителем.

Мы все умеем обращаться как с фактами, так и с обобщенными шаблонами, но чаще имеем склонность к чему-то одному. Точно так же, существуют задачи, для решения которых больше подходит определенный тип мышления. По своему опыту могу сказать, что программисты становятся сильнее, когда понимают свои природные склонности, но учатся адаптироваться при необходимости.

Вот несколько примеров задач, в которых отдается предпочтение определенным типам мышления (все они являются обобщениями)

  • Разработка пользовательского интерфейса требует внимания к большому количеству деталей
  • Спецификации выигрывают от широкого мышления, но могут быть подкреплены конкретными примерами (в качестве тестов обобщений, удобочитаемость улучшается, когда приводятся конкретные примеры, что позволяет убедиться, что обобщения не потеряли связи с реальностью)
  • Масштабируемые системы и архитектуры с большим жизненным циклом требуют абстракций
  • Объектно ориентированное программирование ориентировано на абстракции
  • Коллеги, не являющиеся программистами, и заказчики могут оказаться с конкретным типом мышления. Абстрактно мыслящий человек, общаясь с конкретно мыслящим, рискует оказаться недопонятым, произвести впечатление летающего в облаках. Если вы мыслите абстрактно, хорошо бы научиться общаться с другими людьми на понятном им языке.

Я не ставил перед собой цели показать, какой стиль мышления лучше. Вместо этого я отстаиваю идею самоосознания и тренировки гибкости в мышлении и общении.

Будучи стопроцентным абстракционистом, хочу закончить прекрасным примером абстрактного мышления

Все обобщения ложны. Включая это. Марк Твен

А Марк Твен был абстрактно ориентированным писателем…

habr.com

Многоуровневая абстракция / Хабр

В предыдущей статье мы рассмотрели некоторые подходы к кодогенерации, теперь я хочу взглянуть на многоуровневую абстракцию и произвести некоторый анализ.

Данная статья содержит лишь теорию. Практической будет следующая статья (постараюсь чередовать).

Многоуровневая абстракция


Многоуровневая абстракция — разделение компонента приложения на несколько уровней абстракции так, что на каждом уровне абстракция согласована. Это несколько заумно может звучать. Суть в том, чтобы разделить компонент на несколько уровней, таким образом, чтобы мы могли относительно автономно работать с данным уровнем в его абстракции и не держать в голове информацию о других уровнях.

Зачем вообще делят на уровни абстракции?


1. Борьба со сложностью. На каждом уровне применяются методы именно данного уровня.
2. Уменьшение связности.
3. Обеспечение взаимозаменяемости классов на всех уровнях кроме верхнего.

Многоуровневая абстракция работы с данными


Идем по убыванию уровня абстракции:
* Класс-сущность реального мира
* Провайдер данных
* Реальные библиотеки работы с данными

Пример:
* User
* IUserProvider, SqlUserProvider, XmlUserProvider,…
* SqlClient, XmlDocument,…

При этом мы получаем низкую связность: User знает про интерфейс IUserProvider, SqlUserProvider и XmlUserProvider выполняют IUserProvider и пользутся библиотеками SqlClient и XmlDocument. Более того, объекты определенного уровня абстракции работают только с объектами следующего (нижнего) уровня абстракции, но никак не наоборот, что не допускает циркулярных связей.

Когда возникают проблемы?


1. Обычно в одном проекте несколько многоуровневых абстрактных моделей. Проблемы возникают если несколько абстрактных моделей надо подвергнуть однообразным изменениям. При этом приходится вносить изменения во все промежуточные уровни абстракции включая верхний.
2. При прототипировании накладные расходы на проектирование многоуровневой абстрактной модели могут быть слишком высоки и возможно написание временного кода без уровней абстракции, который придется выкинуть после утверждения прототипа.
3. Абстракция от источников данных может породить (и порой порождает) неоптимальную работу с источниками данных.

Что делать?


Кодогенерация во многих случаях (не всегда) может заменить многоуровневую абстракцию. При этом будут генерироваться конечные классы (из верхнего уровня абстракции), содержащие в себе методы работы с выбранным источником данных.
1. Имея в основе метаданные, мы можем вносить изменения в алгоритмы генерации кода и разом модифицировать всю модель.
2. При наличии метаданных прототип модели можно получить в кратчайший срок.
3. За счет наличия генераторов для каждого источника данных, модель будет сгенерирована с приемлемой оптимальностью работы с выбранным источником данных, учитывая его специфику.

Чем кодогенерация может помочь в сложных моделях


Сложные приложения всегда задают много вопросов. По моим наблюдениям, на бОльшую часть из них можно ответить еще в процессе разработки (например, на сайте нужно кеширование или нет; какая операционная система будет на сервере; использовать буфферизацию вывода или нет…). Если мы ответим на этим вопросы заранее — мы можем избежать лишней сложности программы, лишних действий, лишних проверок и т.п. Более того, кодогенератор сам может собрать в среде назначения некоторые данные заранее, которые он может использовать для оптимизации работы.

Но это не значит, что меньше результирующего кода = проще система. Кодогенератор сам должен быть достаточно качественный для того, чтобы генерировать качественный код.

Кодогенерация + многоуровневая абстрактная модель


Данные подходы не противоречат друг другу и могут использоваться совместно. Например, в ASP.NET существует система хранения личных данных пользователей в профилях (Profile). Там выстроена абстрактная модель с несколькими уровнями абстракции, а сверху лежит ProfileBase. Если список свойств мы зададим в конфигурации, то будет сгенерирован потомок класса ProfileBase — ProfileCommon, который будет содержать те свойства, которые мы указали в конфигурации. Фактически, в конфигурации мы указали метаданные.

В следующей статье мы разработаем определенный несложный кодогенератор.

habr.com

Объектно-Ориентированное программрование — Абстракция

«Я придумал термин „объектно-ориентированный“, и я уверяю вас, что не имел в виду C++».

Alan Kay

Абстракция в ООП — это придание объекту характеристик, которые чётко определяют его концептуальные границы, отличая от всех других объектов. Основная идея состоит в том, чтобы отделить способ использования составных объектов данных от деталей их реализации в виде более простых объектов, подобно тому, как функциональная абстракция разделяет способ использования функции и деталей её реализации в терминах более примитивных функций, таким образом, данные обрабатываются функцией высокого уровня с помощью вызова функций низкого уровня.

Это важный инструмент ООП наряду с полиморфизмом, наследованием и инкапсуляцией.

Абстракция является основой объектно-ориентированного программирования и позволяет работать с объектами, не вдаваясь в особенности их реализации.

Абстракция данных — популярная и в общем неверно определяемая техника программирования. Фундаментальная идея состоит в разделении несущественных деталей реализации подпрограммы и характеристик, существенных для корректного ее использования. Такое разделение может быть выражено через специальный «интерфейс», сосредотачивающий описание всех возможных применений программы

.

Однако как абстракция соотносится с ООП?

Во-первых, абстрагирование не является атрибутом исключительно ООП, да и вообще программирования. Процесс создания уровней абстракции распространяется практически на все области знаний человека. Так, мы можем делать суждения о материалах, не вдаваясь в подробности их молекулярной структуры. Или говорить о предметах, не упоминая материалы, из которых они сделаны. Или рассуждать о сложных механизмах, таких как компьютер, турбина самолёта или человеческое тело, не вспоминая отдельных деталей этих сущностей.

Во-вторых, абстракции в программировании были всегда, начиная с записей Ады Лавлейс, которую принято считать первым в истории программистом. С тех пор люди бесперерывно создавали в своих программах абстракции, зачастую имея для этого лишь простейшие средства. Так, Абельсон и Сассман в своей небезызвестной книге описывают, как создать систему решения уравнений с поддержкой комплексных чисел и даже полиномов, имея на вооружении только процедуры и связные списки. Так какие же дополнительные средства абстрагирования несёт в себе ООП? Понятия не имею. Выделение кода в подпрограммы? Это умеет любой высокоуровневый язык. Объединение подпрограмм в одном месте? Для этого достаточно модулей. Типизация? Она была задолго до ООП. Пример с системой решения уравнений хорошо показывает, что построение уровней абстракции не столько зависит от средств языка, сколько от способностей программиста.

project-pro.do.am

Уровень абстракции (программирование) — это… Что такое Уровень абстракции (программирование)?

У этого термина существуют и другие значения, см. Абстракция (значения).

Уровень абстракции предоставляет способ сокрытия деталей реализации определенного множества функциональных возможностей. Модели программного обеспечения, использующие уровни абстракции, включают семиуровневую модель OSI для протоколов передачи данных компьютерных сетей, библиотеку графических примитивов OpenGL, модель ввода-вывода на основе потоков байт из Unix, адаптированную MSDOS, Linux и большинством других современных операционных систем.

В операционной системе Unix большинство типов операций ввода-вывода рассматриваются как потоки байтов, считываемые или записываемые на устройство. Эта модель потока байтов используется для ввода-вывода в файл, сокет и компьютерный терминал, чтобы обеспечить независимость от устройства ввода-вывода. Для чтения и записи в устройство на уровне приложения программа вызывает функцию открытия устройства, которое может соответствовать реальному устройству, например, терминалу или виртуальному устройству, например, сетевому порту или файлу в файловой системе. Физические характеристики устройства передаются операционной системе, которая, в свою очередь, предоставляет абстрактный интерфейс, позволяющий программисту считывать и записывать байты в устройство. Операционная система затем выполняет действительное преобразование, необходимое для чтения и записи потока байтов в устройство.

Большинство графических библиотек, например, OpenGL, предоставляют в качестве интерфейса абстрактную графическую модель. Библиотека отвечает за трансляцию команд, данных программистом, в специальные комадны устройства, необходимые для рисования графических элементов и объектов. Специальные команды устройства для графопостроителя отличаются от команд устройства для ЭЛТ монитора, но графическая библиотека скрывает зависящие от устройства детали реализации, предоставляя абстрактный интерфейс, содержащий набор примитивов, общеупотребимых для рисования графических объектов.

В информатике уровень абстракции — это обобщение модели алгоритма без реальной реализации. Эти обобщения возникают из общих сходных элементов, которые лучше всего инкапсулируется моделью, выражающей сходство, присутствующее в различных конкретных реализациях. Упрощение, вносимое хорошим уровнем абстракции, позволяет с легкостью использовать повторно полезное понятие или метафору, при этом ситуации, когда это может быть точно применено, легко различимы.

Хорошая абстракция обобщает то, что можно сделать абстрактным; допуск специфики нарушает абстракцию и ее успешное применение требует приспособления к каждому уникальному требованию или проблеме.

Часто уровни абстракции организуются в иерархию уровней абстракции. Сетевая модель OSI содержит семь уровней абстракции. Каждый уровень модели OSI ISO инкапсулирует и рассматривает отдельную часть требований по организации связи, сокращая таким образом сложность соответствующих инженерных решений.

Известный афоризм Дэвида Уилера гласит: Все проблемы в информатике можно решить на другом уровне окольным путем;[2] это часто неверно цитируется с заменой «окольного пути» на «абстракцию». Продолжение от Кевлина Хенни гласит «…за исключением проблем с большим уровнем косвенности.»

Архитектура компьютера

С точки зрения архитектуры компьютера система часто представляется моделью из пяти уровней абстракции: компьютерная техника (см. Слой аппаратных абстракций), прошивками, языком ассемблера, ядр операционной системы и приложений.[1]

Ссылки

  1. 1 2 Tanenbaum Andrew S. Structured Computer Organization. — Englewood Cliffs, New Jersey: Prentice-Hall, 1979. — ISBN 0-13-148521-0
  2. Diomidis Spinellis. Another level of indirection. In Andy Oram and Greg Wilson, editors, Beautiful Code: Leading Programmers Explain How They Think, chapter 17, pages 279–291. O’Reilly and Associates, Sebastopol, CA, 2007.

См. также

dic.academic.ru

Абстракция данных для программирования « AlterVision

В этой статье детально изучается абстракция данных, как способ повышения модульности программы. Абстракция данных позволяет возвести стены между программой и структурами данных. При решении задач нужно выполнять разные операции над данными, поэтому возникает необходимость определить абстрактные типы данных (АТД). На примере простых абстрактных типов данных в статье демонстрируются преимущества ATI вцелом. Это позволяет сосредоточиться решении отдельной задачи, не отвлекаясь на другие. Таким образом, программу легче писать, читать и модифицировать. Модульность программы позволяет локализовать ошибки, а также исключить избыточный код.

При этом следует сосредоточивать внимание на том, что именно делает модуль, а не на том, как он это делает.  Это позволяет разрабатывать функции в относительной изоляции друг от друга, обращая внимание лишь на то, что они делают, и не вникая в детали их внутреннего устройства.  Принцип сокрытия информации (information hiding) подразумевает не только утаивание деталей внутреннего устройства модуля от других частей программы, но и невозможность доступа к ним извне. Сокрытие информации ассоциируется со стенами, возведенными между разными частями программы. Эти стены предотвращают перепутывание данных.

Оно невелико и не позволяет увидеть детали внутреннего устройства функции, но достаточно широкое, чтобы обмениваться через него данными. Например, в функцию сортировки через это окошко можно передать массив и получить его обратно уже упорядоченным. То, что функция получает извне, и то, что она возвращает внешнему миру, описывается в терминах ее спецификации, или контракта (contract) в нем указывается, что именно делает функция, и какие условия для этого должны выполняться.

В общих чертах, их можно свести к трем разновидностям:
1. Добавление (add) данных в набор.
2. Удаление (remove) данных из набора.
3. Проверка (ask question) данных, содержащихся в наборе.

Упорядоченный массив совместно с алгоритмом бинарного поиска можно рассматривать в качестве абстрактного типа данных, позволяющего решить эту задачу.

Тогда — и только тогда — можно приступать к реализации операций над структурой данных. Если операции реализованы правильно, их можно применять и в остальной части программы, т.е. считается, что условия контракта выполнены.
В спецификациях указывается, что делают операции АТД, но не описывается их реализация

Для того чтобы лучше понять разницу между абстрактными типами данных и структурами данных, рассмотрим морозильное устройство. На его вход поступает вода, из которой получается либо охлажденная вода, либо измельченный лед, либо кубики льда, в зависимости от того, на какую кнопку нажать. Кроме того, имеется индикатор, который загорается, если льда внутри нет. Это устройство представляет собой пример абстрактного типа данных. Аналогом данных является вода, а операциями — охладить, измельчить. На этом уровне проектирования нас не интересует, как именно морозильное устройство выполняет указанные операции. Если мы хотим измельчить лед, незачем нам вдаваться в технические тонкости устройства холодильника, если он и так работает правильно. Таким образом, описав функции, выполняемые морозильным устройством, операции, использующие измельченный лед, можно применять, не зная, как он получается.

Морозильное устройство для получения охлажденной воды, измельченного льда и кубиков льда.
Однако в конце концов кто-то же должен создать морозильное устройство. Как все-таки получается измельченный лед? Сначала нужно сделать кубик льда, а затем измельчить его с помощью двух стальных роликов, или разбить молотком на мелкие кусочки. Для этого можно придумать много способов.
Несмотря на то что владельца холодильника не интересуют технические подробности, он или она хотят, чтобы устройство работало как можно эффективнее.    Те же самые понятия используют при выборе структуры данных для реализации абстрактного типа данных в языке С. Даже если вы не реализуете АТД сами, а используете уже готовые компоненты, вы как и человек, купивший холодильник, должны стремиться, крайней мере, к эффективности.
Таким образом, внутренний механизм устройства не только скрыт от пользователя, но и недоступен. Кроме того, механизм выполнения одной операции недоступен для другой.
Такой модульный подход имеет преимущества. Например, операцию мельчить можно усовершенствовать, изменив ее модуль. Кроме того, можно добавить новую операцию, подключив к машине новый модуль и оставив первые три операции без изменения. Таким образом, в холодильнике применяется и абстракция, и принцип сокрыт информации.

Этот процесс напоминает использование торговых автоматов. Вы нажимаете кнопки и получаете нечто в ответ. Внешний дизайн автомата подсказывает вам, что нужно делать, так же как спецификации АТД описывают операции и их предназначение. Раз вы пользуетесь подсказками автомата, технические детали его внутреннего устройства становятся для вас безразличными. Аналогично, согласившись на доступ к данным только через операции АТД, можно забыть о любых изменениях структур данных, реализующих этот АТД.
На следующих страницах мы покажем, как использовать абстрактные типы данных для отделения операций над данными от реализации этих операций. Для этого мы рассмотрим несколько примеров АТД.
Описанные все списки, в которых манипуляции над элементами производились либо в начале, либо в конце, либо и в начале, и в конце, не соответствуют реальному списку продуктов. Нам может понадобиться доступ к любому элементу списка. Это значит, что мы можем просматривать элемент, находящийся на позиции и, удалять его или вставлять новый элемент в эту позицию. Эти операции являются частью абстрактного типа данных под названием список (list).

Операции над абстрактным списком:
— Создать пустой список.
— Уничтожить список.
— Определить, пуст ли список.
— Определить количество элементов в списке.
— Вставить элемент в указанную позицию списка.
— Удалить элемент, находящийся в указанной позиции списка.
— Просмотреть (извлечь) элемент, находящийся в указанной позиции списка.
Абстрактный список представляет собой упорядоченный набор элементов, каждый из которых имеет свой номер.
Если поведение абстрактного типа описано правильно, можно приступать к разработке приложения, манипулирующего его данными, пользуясь лишь названиями операций и не вникая в детали их реализации. Допустим, к примеру, что мы хотим вывести на экран элементы списка. Несмотря на то что стены, отделяющие реализацию абстрактного списка от остальной программы, скрывают способ его хранения, можно написать функцию displayList, операции, определенные для этого типа.

Поскольку абстрактный список реализован правильно, функция displayList будет успешно выполнена. В этом случае функция retrieve сможет извлечь любой элемент списка, так как значение параметра position всегда корректно, следовательно, аргументом success можно пренебречь.

Если удаление выполнено успешно, функция remove присвоит параметру success значение true. Проверив значение этого параметра, функция replace приступит к вставке, только если удаление действительно произошло.  Операции абстрактного типа данных можно применять, не вникая в детали их реализации
В обоих примерах, описанных ве, мы не вникали в детали реализации списка. Нам было все равно, хранятся ли его записи в массиве
или в другой структуре данных. Это относится и к созданию программ на языке С. Кроме того, поскольку операции iInsert и replace не зависят от реализации типа, их содержание никак не изменяется, именно поэтому такие операции часто называют турникетными. Итак, функционирование абстрактного типа данных можно определять независимо от его реализации. Имея такую спецификацию и ничего не зная о том, как именно будет реализован АТД, можно приступать к разработке приложения, применяющего операции АТД для доступа к его данным.

www.av13.ru

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *