LINUX.ORG.RU

Зачем нужно ООП

 


2

3

Далёк я буду от правды если скажу, что единственная причина появления ООП - нельзя было сказать draw(circle) и draw(rectange) в одной программе (где rectange и circle - переменные с различными структурами)?

★★★★★
Ответ на: комментарий от TDrive

ох жеж.

в С плохо(не вполне всем удобно через static всем рулить) с модульностью было ( до пространств_имён С++) поэтому сокрытие прикрутили через доступ к полям тем более атд были модны.

в рантайм-языках объект по сути сам решает какой у него интерфейс сей момент т.е. есть не столько сокрытие сколько лицемерие.

qulinxao ★★☆
()
Ответ на: комментарий от Freyr69

reuse кода с уже отлаженным поведением (сортировки, поиск) не нужен

напиши функцию - будет reuse кода с уже отлаженным поведением

Канонический пример:

class Person {
    public String givenName;
    public String lastName;
}
Задача - сделать поиск по шаблону в имени или фамилии. Сделали (написали функцию).
Забыли отчество! Добавили в класс:
class Person {
    public String givenName;
    public String middleName;
    public String lastName;
}
Поменяли функцию поиска.
А, блин - оказывается, у юзера есть ещё и теги, и искать надо еще и по тегу!!!
Снова правим функцию поиска?!
А не проще ли было сделать итератор:
interface Matcher { public boolean match(Person p); }
class PersonUtils {
    public static Vector<Person> findAll(Vector<Person> src, Matcher filter) {
        Vector<Person> ret = new Vector<Person>();
        Iterator<Person> i = src.iterator();
        while (i.hasMoreElements()) {
            Person p = i.nextElement();
            if (filter.match(p)) ret.add(p);
        }
        return ret;
     }
    public static Person findFirst(Vector<Person> src, Matcher filter) {
        Vector<Person> ret = new Vector<Person>();
        Iterator<Person> i = src.iterator();
        while (i.hasMoreElements()) {
            Person p = i.nextElement();
            if (filter.match(p)) return p;
        }
        return null;
     }
}
Всё, мы более не меняем поиск, вообще - мы просто строим новые фильтры:
class RegexFilter {
    private String pattern;
    public RegexFilter(String pattern) { this.pattern = pattern; }
    public boolean match(Person p) {
        return Regex.match(p.firstName,pattern)||Regex.match(p.lastName,pattern);
    }
}
Более не нужно писать код поиска, достаточно просто реализовывать новые (или модифицировать существующие) фильтры. И не надо дублировать код поиска нужной записи в обоих методах. Если надо сделать поиск по тегам - пишем соответствующий фильтр. Надо сделать поиск по тегам и ФИО - новый фильтр. Поиск по регулярным выражениям заменить на поиск по точному совпадению? Еще один фильтр. Расширение с минимальными затратами.

P.S.: да, я в курсе, что все такие типовые контейнеры и операции уже реализованы. Как раз за счет такого разделения, когда

P.P.S.: только не надо говорить про то, что ты передашь в функцию поиска функцию - я попрошу тебя реализовать поиск параллельно в двух потоках по разным критериям и с интересом посмотрю на то, как ты будешь выкручиваться не прибегая к замыканиям (ведь замыкание есть суть тот же объект с набором неявно или явно заданных полей и единственным методом)

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

ведь замыкание есть суть тот же объект с набором неявно или явно заданных полей и единственным методом

Гм... а продолжение это тоже какой-то объект?

Вообще, замыкания и продолжения дают всю необходимую гибкость. Что касается поиска, например, то написать один раз при определении коллекции (define myseq-sort (make-sort myseq-len myseq-elt)) не так сложно. И при этом получаем нормальную функцию, а не виртуальный метод, который на каждый вызов проверяет (использует) тип объекта.

monk ★★★★★
()
Ответ на: комментарий от anonymous

Смысл инкапсуляции (и ооп) в том, чтобы гарантировать зависимость корректности крупной системы от корректности маленького интерфейса.

В нормально спроектированных языках эту функцию (инкапсуляции) выполняют модули.

monk ★★★★★
()
Ответ на: комментарий от qulinxao

сообщение это набор бит приходящий актору. актор диспатчит сообщение , меняет(возможно) своё состояние и также делает 0 и более сообщений.

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

pef-secure
()
Ответ на: комментарий от monk

В нормально спроектированных языках эту функцию (инкапсуляции) выполняют модули.

Ну да, классы - это и есть «усовершенствованные» модули.

anonymous
()
Ответ на: комментарий от no-dashi

Канонический пример:

как всё сложно, когда используются неподходящие инструменты.

@founs_persons = grep {$_->{firstName} eq 'Robert'} @persons;

и никакой «ооп» не нужен.

pef-secure
()
Ответ на: комментарий от no-dashi

только не надо говорить про то, что ты передашь в функцию поиска функцию

А разве ты не тоже самое желаешь, передавая Matcher?

Кстати, вопрос тем, кто на сишке ооп пишет, если в структуре есть указатели на функции, единственный способ передать этим «методам» указатель на структуру - указать this в качестве аргумента?

Freyr69 ★★★
()
Ответ на: комментарий от no-dashi

Да-да, а в awk можно ваще написать (/Robert/) { print $0; }, и чо?

Ты разницы не видишь? Есть набор гибкой стркутуры, те передаёшь подходящую функцию матчинга. Не пугай меня своими навыками программирования, я тебя плохо знаю и априори хорошо отношусь, но ты меня начинаешь пугать. Начинай думать перед ответом.

pef-secure
()
Ответ на: комментарий от no-dashi

а теперь на бис - но по тегам :-)

конкретизируй что именно «по тегам». и что именно тебы непонятно в функции матчинга.

pef-secure
()
Ответ на: комментарий от J-yes-sir

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

dizza ★★★★★
()
Последнее исправление: dizza (всего исправлений: 1)
Ответ на: комментарий от Freyr69

А разве ты не тоже самое желаешь, передавая Matcher?

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

no-dashi ★★★★★
()
Ответ на: комментарий от anonymous

классы - это и есть «усовершенствованные» модули.

Именно так. Взяли структуры с наследованием и модули. Смешали и получили ООП. Вот только наследование для модулей и структур должно быть в противоположные стороны. Вот здесь люди попытались реализовать как должно быть: http://common-lisp.net/~frideau/lil-ilc2012/lil-ilc2012.html Также частичным решением можно считать интерфейсы в Java.

monk ★★★★★
()
Ответ на: комментарий от monk

Вот только наследование для модулей и структур должно быть в противоположные стороны.

С чего бы?

anonymous
()
Ответ на: комментарий от no-dashi

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

Да, проходили уже это, функция = объект, ясно.

А твой экземпляр - просто таже функция, это уже философия.

Суть как раз в том, что не хорошо инкапсулировать код и функции в один объект, естественно ооп иногда полезно, и там где его удобно использовать - лучше использовать, но превращать все в объекты черевато.

Freyr69 ★★★
()
Ответ на: комментарий от pef-secure

конкретизируй что именно «по тегам».

class Tag {
    String local_name;
    String intl_name;
    public boolean equals(Object v) {
        if (!v instanceof String) return false;
        return (local_name.equals(v) || intl_name.equals(v));
    }
}
class Person {
    Vector<Tag> tags;
}
class TagFilter extends Filter {
    Tag tag;
    public TagMatcher(Tag tag) { this.tag = tag; }
    public boolean match(Person p) { return p.tags.contains(tag); }

Примерно так

no-dashi ★★★★★
()

Далёк я буду от правды

Да, далёк. Причина появления и доминирования ООП в том, что людям естественно думать в терминах объектов и их (взаимо)действий. Естественность влечет за собой эффективность труда и сниженный порог вхождения.

Manhunt ★★★★★
()
Ответ на: комментарий от qulinxao

на виденье_восприятие влияет предистория смотрящего

Да, предыстория, причем в разрезе эволюции видов. Восприятие мира в терминах объектов в людях захардкожено где-то глубоко в ДНК. Этакий аппаратный акселератор.

Manhunt ★★★★★
()
Ответ на: комментарий от no-dashi

Примерно так

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

pef-secure
()
Ответ на: комментарий от pef-secure

Так он сам признал, что вместо класса может быть просто функция, просто он ее считает тоже за объект и не труЪ.

Freyr69 ★★★
()
Ответ на: комментарий от Freyr69

Суть как раз в том, что не хорошо инкапсулировать код и функции в один объект

А иногда как раз нехорошо НЕ капсулировать код и данные. В том же примере с поиском - можно реализовать проверку соответствия маске поиска как в объекте, так и в фильтре. А впоследствии - перетащить из фильтра в объект или из объекта в фильтр. Сделать display_name агрегированного контакта полем объекта, передумать - и сделать его же уже вычисляемым на основании агрегированных в контакт контактов. Хранить значения в массивах соответствующих классов значений - или в одном массиве. Не меняя основного управляющего кода.

no-dashi ★★★★★
()

Почему это в Development? Где тег «платиновые треды ЛОРа»? Откуда столько школьников ООП хейтеров в треде? Каникулы же ещё не начались.

peregrine ★★★★★
()
Ответ на: комментарий от qulinxao

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

TDrive ★★★★★
()
Ответ на: комментарий от Freyr69

Так он сам признал, что вместо класса может быть просто функция

НЕ функция(!). Чтобы это работало нормально и было юзабельно - функция должна быть с контекстом (да-да, любимое замыкание как пример такой функции). И всего отличия - явное декларирование контекста - да и то, с эволюцией языков эта грань все более размывается. Можно писать на жабе/шарпе в функциональном стиле, на них же в объектно-ориентированном, и на них же в процедурном.

no-dashi ★★★★★
()
Ответ на: комментарий от Freyr69

Суть как раз в том, что не хорошо инкапсулировать код и функции в один объект,

Суть как раз в том, что хорошо.

anonymous
()
Ответ на: комментарий от no-dashi

функция должна быть с контекстом

Это в ваших с++/java замыкания сложно делать. На нормальном динамическом языке нет проблем.

pef-secure
()
Ответ на: комментарий от J-yes-sir

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

dizza ★★★★★
()
Ответ на: комментарий от peregrine

Вот когда будет более 2000 постов в теме, все пересрутся, вызовут друг друга на дуэли на кладбище на лопатах... Вот тогда он станет платиновым

no-dashi ★★★★★
()
Ответ на: комментарий от pef-secure

Ваш нормальные динамические языки уже научились строгой типизации с compile-time проверками, которые вычищают 75% ошибок на этапе компиляции?

no-dashi ★★★★★
()

ООП - это когда первый параметр функции пишут перед функцией. Всё остальное можно делать без ООП.

anonymous
()

Инкапсуляция, полиморфизм, наследование. Если ты не знаешь, что это такое - оно тебе не нужно, забей

Ford_Focus ★★★★★
()
Ответ на: комментарий от anonymous

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

dizza ★★★★★
()

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

anonymous
()
Ответ на: комментарий от no-dashi

динамические языки уже научились строгой типизации

динамические языки

строгой типизации

parse error

umren ★★★★★
()
Ответ на: комментарий от no-dashi

Ваш нормальные динамические языки уже научились строгой типизации с compile-time проверками, которые вычищают 75% ошибок на этапе компиляции?

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

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

pef-secure
()
Ответ на: комментарий от anonymous

ООП - это когда первый параметр функции пишут перед функцией. Всё остальное можно делать без ООП.

смешиваешь вопросы синтаксиса и сути. первые компиляторы с++ компилировали в си. но синтаксис си, конечно, не позволял писать «первый параметр функции перед функцией».

pef-secure
()
Ответ на: комментарий от Ford_Focus

Инкапсуляция, полиморфизм, наследование. Если ты не знаешь, что это такое - оно тебе не нужно

а если знаешь?

jtootf ★★★★★
()
Ответ на: комментарий от anonymous

Вот только наследование для модулей и структур должно быть в противоположные стороны.

С чего бы?

Возьми sequence и sorted-sequence. Структурно упорядоченная последовательность — подвид неупорядоченной. То есть sorted-sequence должно быть можно использовать везде, где можно использовать sequence.

Но модуль для sequence наоборот является расширением модуля для sorted-sequence, так как кроме add должно быть insert и append.

monk ★★★★★
()
Ответ на: комментарий от Freyr69

Кстати, вопрос тем, кто на сишке ооп пишет, если в структуре есть указатели на функции, единственный способ передать этим «методам» указатель на структуру - указать this в качестве аргумента?

Да. Но выглядеть это по-разному может.

Частенько объект - это один указатель, а «интерфейс»(структурка с указателями на функцию) - другой.

int
foo(my_iface_t *iface, some_object_t *obj, int x, char *s)
{
    ...
    iface->bar(obj, x, s);
    ...
}

Иногда же vtbl - поле объекта

int
foo(some_object_t *obj, int x, char *s)
{
    ...
    obj->vtbl->bar(obj, x, s);
    ...
}

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

anonymous
()
Ответ на: комментарий от pef-secure

то в ваших с++/java замыкания сложно делать.

Да нормально там их делать.

anonymous
()
Ответ на: комментарий от Ford_Focus

Инкапсуляция, полиморфизм, наследование. Если ты не знаешь, что это такое - оно тебе не нужно, забей

От ООП из этого списка только наследование(остальное есть и без ООП). Но всю пользу от него дают расширяемые модули(Limbo) или деление на структуры/сигнатуры(SML). Нет?

anonymous
()
Ответ на: комментарий от umren

Да-да. Типизация может быть строгой или слабой. Динамической или статической. И это ортогональные признаки. Си - статическая слабая типизация, Python(прости хосподи) - динамическая строгая.

anonymous
()
Ответ на: комментарий от anonymous

Но всю пользу от него дают расширяемые модули (Limbo)

А как в Limbo сделать расширение модуля?

В Racket просто

(require base-module)
(provide (all-from-out base-module) new-fun1 new-fun2)

или если надо переопределить что-то

(require (except-in base-module change-fun))
(provide (all-from-out base-module) change-fun)

monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.