Ответы пользователя по тегу ООП
  • Где можно прочитать про всю суть ЯПов под капотом?

    Все советуют вам Книгу Дракона. Книга, безусловно, отличная и классическая, но я что-то по вашему вопросу сомневаюсь, что вам нужно именно это - реализация и механика/синтаксис языков. Попробуйте Programming Language Pragmatics - мне кажется там ответы на ваши вопросы.
    Ответ написан
    Комментировать
  • Неполцноенное ООП в javascript и значение этого?

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

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

    В C++ и C# есть классовое ООП, соединённое с номинативной стратегией типизации. В JS и Lua есть прототипное ООП, которое в TypeScript приправляется структурной типизацией. В Rust по сути нет наследования, но есть полиморфизм. В Ruby есть концепция метаклассов, которая не особо известна в других языках. Все делают по-своему, говорить, что в каком-то языке "истинное" ООП - глупо, потому что об этом нет договорённости.

    Исторически есть две крупные "школы" ООП - школа языка SIMULA и школа языка Smalltalk, вот можете почитать об этом. К этим школам добавляется ещё прототипный подход, который впервые появился в языке Self, джаваскрипт тут Америку миру не открыл. История языков программирования вообще очень длинная и интересная штука, большинство идей в современных промышленных языках были изобретены значительно ранее в других языках, экспериментальных или академических.

    JS как язык отвратителен не потому, что в нём "ненастоящее" ООП, а совсем по другим причинам.
    с вашей идееологией интересно(с которой я согласен), как вы относитесь к тсу?

    Вы спросили не у меня, но позволю себе ответить - TypeScript это лучшее, что было с JS, потому что он делает программирование на JS возможным. Обратите внимание - с точки зрения ООП тайпскрипт ничего нового не вносит, так что на мой взгляд дело вообще не в ООП. А например в том, что в JS никак бл..ь не доедут записи. Как можно в 2023 году программировать на языке без таких элементарных вещей? За что нам такое наказание?
    Ответ написан
  • SOLID.LSP + ООП.Полиморфизм = противоречиe?

    Появилось требование - изменить формат некоторых отчетов на CSV.

    А кто сказал, что может появиться такое требование? Вернее, что вы сможете его удовлетворить без изменения контракта?

    Ведь у вас какой контракт? Что метод MakeReport возвращает html-отчёт? Так как же вы вообще сможете реализовать возврат CSV, не поменяв контракт?

    А вот если вы таки поменяете контракт, например скажете что "MakeReport возвращает поток (текстовый или двоичный) конечного размера", то тогда генерация и возврат CSV вполне себе лягут в такой контракт. Конечно, такой контракт уже будет куда более общим - даже тестировать в нём будет особого нечего (кроме того что отчёт вообще сгенерировался и имеет ненулевую длину).

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

    Всё просто, не так ли?

    Принцип подстановки говорит - я поставлю рамки, ограничения (т.е. контракт), и все экземпляры подклассов должны ему удовлетворять. Полиморфизм говорит - отлично, значит у нас возможность определить СПЕЦИФИЧНОЕ поведение, которое может отличаться от других специфичных поведений, но при этом все они будут делать что-то вполне ожидаемое и ЗАРАНЕЕ ОГОВОРЕННОЕ.

    Сам факт того, что вы составляете СОГЛАШЕНИЯ, выполнения которых ожидают клиенты класса, даёт вам право ВО ВСЕХ ОСТАЛЬНЫХ аспектах вести себя КАК ВАМ ВЗДУМАЕТСЯ (ну я немного преувеличил, но суть такова) в каждом из подклассов.
    Ответ написан
    Комментировать
  • Что значит такое ограничение в заголовке класса?

    Nipheris
    @Nipheris Куратор тега C#
    Чтобы в этом ограничении был смысл, класс Game должен быть дженериком с параметром типа TFamilyType.

    Ограничение говорит, что тот тип, который вы подставите вместо TFamilyType при использовании класса Game, должен реализовывать интерфейс IFamily и иметь конструктор без параметров.
    Ответ написан
    1 комментарий
  • ООП в C# c точки зрения Алана Кея?

    Nipheris
    @Nipheris Куратор тега C#
    Я посмотрел основные принципы ООП с точки зрения Алана Кея и не могу понять, чего он хотел.

    Неудивительно. Изначально ООП было прежде всего идеей и не имело формального описания, такого как реляционная алгебра для РБД. То, что не имеет формального описания может быть по-разному трактовано и понято, или не понято вовсе.
    Да. Этого нет.

    Ошибаетесь. Есть аналог "сообщений" - это методы объектов. Вызов метода - это аналог посыла сообщения. Просто вы не привыкли рассматривать это с такой точки зрения. Например, в Objective C, в котором ООП смолтоковского стиля, так прямо и говорят. В языках с Simula-подобным ООП методы не называют сообщениями, т.к. в отличие от Smalltalk-стиля выбор кода для вызова (обработки метода/сообщения) выполняется компилятором, а не самим объектом.
    Каждый объект имеет независимую память, которая состоит из других объектов

    Пожалуй здесь речь идёт об инкапсуляции.
    Стоп. Разве это не то, что я написал в пункте 4?

    Нет. В пункте 4 вводится само понятие классификации - что среди неупорядоченного набора всевозможных объектов вы выделяете подмножества объектов, "похожих" друг на друга. Здесь ещё не идёт речи о том, будут ли у них общие методы или ещё что-то конкретно. Речь о самой идее выделения объектов во множества по каким-либо признакам. В пункте 5 уже делается заключение, что если уж мы выделили некоторое подмножество объектов, то грех этим не воспользоваться и не задать одно и то же поведение сразу для всего подмножества (грубовато описал, но как то так и есть).
    Если у меня есть класс Dog, описывающий собаку, то от какого мифического единого общего класса она должна наследоваться?

    System.Object. Да, вы уже от него унаследовались, прямо или через других предков. С точки зрения среды исполнения не всё чем вы оперируете, является объектом, например примитивные значения. Однако с точки зрения языка можно сказать что int "является объектом" т.к. значение int может быть приведено к типу object. От себя лично скажу, что целесообразность концепции "всё - объект" весьма сомнительна по ряду причин.
    Ответ написан
    1 комментарий
  • Не всегда же называть методы глаголами?

    Когда вы пользуетесь fluent interface - вы всегда создаёте маленький язык внутри другого языка. Поэтому нет ничего странного в том, что вам хочется вспомогательные конструкции называть по иным правилам.
    Ответ написан
    Комментировать
  • Как реализовать инкапсуляцию в JS?

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

    Более правильная реализация:
    https://developer.mozilla.org/en-US/docs/Web/JavaS... , Emulating private methods with closures

    проблема у такого подхода - всё это делается ценой рантайма - на каждый объект будут свои инстансы методов. Хотите нормальную инкапсуляцию? Берите TypeScript.
    Ответ написан
    Комментировать
  • Правила хорошего тона protected или private?

    А почему вы по умолчанию public не ставите, если выбираете между public и private? Наверное потому что вам инкапсуляция нужна?

    Ситуация с дочерними классами ничем не отличается. Не стоит делать метод protected по умолчанию по той же причине, по которой его не стоит делать public по умолчанию.
    Ответ написан
    Комментировать
  • Как принято у программистов: использовать для переменной свойство или давать параметр в каждом методе?

    Два примера решения одной задачи

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

    Это настолько разные примеры, что даже непонятно, как вам эту разницу объяснить.
    Ответ написан
    Комментировать
  • Как изменить тип параметра в унаследованном методе C#?

    Nipheris
    @Nipheris Куратор тега C#
    То, что вы просите, невозможно сделать по одной простой причине. Наследование в .NET бывает только "настоящее", т.е. когда устанавливается отношение is-a. Ваш MyTCPStream не может быть Stream-ом, если не реализует метод Read (Byte[], Int32, Int32). Спросите себя - что произойдёт, если я скастю объект MyTCPStream к Stream, и попытаюсь вызвать Read(Byte[]...)?

    Вы конечно можете в теле метода бросить InvalidOperationException, но это однозначно признак неверно выбранной абстракции. Лично я не понимаю, зачем вам мог понадобиться TCPStream, из которого вы читаете не байты, а символы.

    Для реализации процесса чтения более сложных объектов (а символ это более сложная штука, т.к. его представление в потоке зависит от кодировки) в дотнете есть TextReader и его наследники. Было бы хорошо, если б вы описали изначальную задачу - возможно мы посоветуем вам что-то полезное, а не странные хаки.
    Ответ написан
    3 комментария
  • Зависимости внутри системы лучше строить от интерфейсов или абстрактных классов? Когда лучше использовать абстрактный класс и когда интерфейс?

    По-моему зависимости внутри системы от интерфейсов более гибкие.

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

    LoggerInterface

    В каждом ОО-языке свои конвенции именования интерфейсов, но скорее всего лучше назвать просто Logger. Вы же не пишете Class в конце имени каждого класса.

    Подскажите, пожалуйста, как правильно определить когда использовать интерфейс и когда абстрактный класс?

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

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

    Сначала ES6, потом TypeScript. Если у вас встают такие вопросы, в "классическом" JS (ES5 и ниже) вы не найдете ответов. Например, посмотрите как компилит классы TS или Бабель.

    В ES5 есть только две вещи, имеющие какое-то отношение к ООП - выстраивание объектов в цепочку прототипов и объект как словарь ключ-значение.
    Ответ написан
    Комментировать
  • Существует ли красивая конструкция для делегирования реализации интерфейса?

    Не совсем понятно, чего вы хотите. Вернее, чего хотите - понятно, непонятно - почему.

    Если вы хотите абсолютно все методы делегировать к инстансу IR - то почему бы вам просто не возвращать инстанс IR через интерфейс I из объекта A - зачем самому A реализовывать I?

    Если же посредничество A все-таки необходимо, то значит, что вы хотите дать этому какую-то смысловую нагрузку. Т.е. раз вам хочется, чтобы A сам реализовал I, то значит вам хочется, чтобы он скрывал факт того, что вызовы на самом деле делегируются к инстансу IR.

    Раз вы хотите, чтобы факт делегирования скрывался от клиента класса A, то вероятно, со временем, вы захотите поменять логику делегирования, и делегировать, например, не к IR, а к другой реализации интерфейса I (иначе зачем вам такое сокрытие факта делегирования к IR). А раз так, то вполне логично, что вы должны явно реализовать методы, делегирующие себя к методам IR.

    К чему я это всё? Конечно, можно себе представить, что код делегирования генерируется автоматически на основе конструкции вроде вашей (implements I by delegate), однако: а) это довольно частный случай, чтобы добавлять в язык синтаксический сахар для этого, плюс наверняка возникнет ряд вопросов реализации, на которые не будет однозначного ответа; б) я думаю такое реализуемо в языках с мощными макросами, но мне приходят в голову только те, которые вы врядли будете использовать, например Nemerle или Lisp. А, ну и на препроцессоре C++ такое можно сделать.
    Ответ написан
    2 комментария
  • Какой из этих подходов в ООП лучше и как они называются?

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

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

    Второй вариант подразумевает, что магия может полностью задаваться извне, и Magick только кастит её, но в её "формировании" не участвует.

    Сейчас вы не решили для себя, что такое Magick. Вам нужно это сделать, и вопрос отпадёт сам собой.
    Ответ написан
    1 комментарий
  • Какие существуют архитектуры взаимодействия с базой данных?

    А вы по какому признаку хотите классифицировать? Я вот могу назвать такую архитектуру клиент-серверной, а еще многослойной.
    Какие альтернативы? Ну, во-первых сам WCF может быть очень разный, и SOAP, и REST. Во-вторых, некоторые клиенты (например, административного характера) могут цепляться напрямую к базе (к примеру, они имеют доступ к серверу по VPN), и тогда веб-сервиса между БД и клиентом нет.
    Также, приложение может работать не сразу со веб-сервисом/БД, а к примеру складировать данные в локальную базу (какой-нибудь SQLite), а потом её синхронизировать с основной БД - также через сервис или напрямую (зависит от доверия к клиентскому приложению) - это сложнее с точки зрения наладки всего процесса, но иногда просто необходимо, если связь с центральным сервером БД не гарантирована (иногда приложения на мобильных устройствах должны работать и вне большого города и толстого 4G канала).

    WCF-служба может пользоваться ORM или программист может заранее составить все SQL-запросы.
    WCF-служба может хоститься и на IIS, если это удобно. Хотя, если она выполняет в БД фоновые операции, то вполне правильно и логично хостить её в Виндовом сервисе.

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

    Вас что конкретно интересует? Нужно хотя бы говорить о клиенте или сервисе отдельно, т.к. это сами по себе крупные компоненты со своей архитектурой.
    Ответ написан
  • Как связать две иерархии классов?

    Nipheris
    @Nipheris Куратор тега C#
    Если вы обязаны жить с разделением архитектурных слоёв, о котором вы упомянули и не можете ничего поменять: первый вариант "тип" - "инициализатор" вижу наиболее удобным. Все равно придется добавлять маппинг при добавлении нового типа объекта.
    Вообще можно конечно продолжить извращение и воспользоваться рефлексией и сделать автомаппинг классов "модели" на наследников GameObject. Например, искать все классы "модели" в определенном неймспейсе и искать такие же в другом (которые, в свою очередь, будут наследниками от GameObject).

    Вообще, вы в каком-то смысле идете вразрез с архитектурой самого движка, т.к. GameObject-ы - это не только "представление", а и модель тоже. Я понимаю, что вы наверное не хотите создавать тяжелые GameObject-ы, когда они вроде как не нужны еще (т.е. не в области видимости), но возможно, если не добавлять их в сцену, они не будут нагружать движок.
    В общем, у меня есть сомнения в том, что такое разделение на модель и представление при использовании Unity - хорошая практика.
    Ответ написан
    1 комментарий
  • Как правильно спроектировать службу?

    Во-первых вам нужно ОЧЕНЬ ЧЕТКО понять принципиальную разницу между терминами "WCF service" и "windows service", т.к. общего между ними немного. Первое это про веб-сервисы, второе - это тоже что и демоны в *nix-системах. Первое это про архитектуру распределенной системы, второе это про жизненный цикл программы (как, когда и кем запускается/останавливается).

    Поэтому:
    1) если разработка под Винду, и
    "служба должна выполнять в фоне некоторые действия с бд"

    то почитайте про Windows Service - на шарпе такие пишутся относительно просто. Это не единственный способ запустить процесс, который будет крутиться и сам что-то делать в базе, но он предпочтителен.
    2) если взаимодействие с клиентом подразумевается не по самодельному протоколу, а например по HTTP, то вам срочно нужно ознакомиться с тем, что такое веб-сервисы/веб-API и какие они бывают. Если вы уже понимаете что это такое, то вам нужно выбрать способ реализации под Дотнетом.

    Подскажите, это можно сделать в рамках одной службы или нет?

    Если под службой понимается Windows-служба, то можно. Стоит ли - другой вопрос, зависит от тех действий, которые вы хотите выполнять в фоне, архитектуры БД и политики работы с ней.
    Ответ написан
    Комментировать