Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
DTO — это всего лишь представление кусочка данных, который был отображен в (mapped into) объектно-ориентированный язык.
DTO не нарушают инкапсуляцию, потому что они попросту не объекты.
Не позволяйте вашим инструментам обманывать вас. .NET Framework очень-очень хочет, чтобы вы думали, что DTO — это объекты.
Расскажите это разработчикам библиотек. Узнайте что с ними сделают пользователи библиотек за такое, когда после очередного update надо будет переделывать свой проект.
return field; и this.field = field; Тем самым ничем не отличаясь от простого public Field field;Большинство getters/setters являются простым return field; и this.field = field;
Под инкапсуляцией я понимаю просто скрытие реализации.
От кого сокрытие?От пользователя экземпляра класса.
Представим, что я разработчик ядра, а Вы разработчик модулей… Нарушена ли инкапсуляция?Если о реализации этих методов ничего не известно, то ответить на этот вопрос нельзя. Может быть нарушена, может быть нет. Пользователь может надеяться, что не нарушена.
Нарушена ли инкапсуляция?
а. просто устанавливают и получают значение защищённого свойства $name.Да.
б. просто устанавливают и получают значение защищённого свойства $value.Да.
в. просто устанавливают и получают значение защищённого свойства $name и выводят его значение на экран.Да.
г. просто устанавливают и получают значение защищённого свойства $name и выводят его значение записывают в лог.Да.
д. просто устанавливают и получают значение защищённого свойства $name, но перед установкой умножают на 100, а получаемое значение увеличивают в 100 раз.Да.
е. просто устанавливают и получают значение защищённого свойства $name, но при этом содержат по 15 строчек комментариев о том как метод будет изменён в будущем.Да.
ё. обфусцированы и просто устанавливают и получают значение защищённого свойства $name.Да.
ж. обфусцированы, но логика в них сложнее, чем в предыдущем варианте.Не могу ответить, зависит от логики.
От кого сокрытие?
От пользователя экземпляра класса.
Если о реализации этих методов ничего не известно
Не могу ответить, зависит от логики.
Значит реализация от Вас скрыта.
Так… как тогда различить где скрывается реализация от пользователя и где нет.
книги «Совершенный код» С. Макконнелл
Или пометьте согласно соглашениям в команде/сообществе что доступ к этому полю/свойству/методу не должен использоваться клиентским кодом
var fullName = person.getFirstName() + person.getLastName() person.setName("ololo");
person.someMethod();
interface IBuilder
{
string build(string firstName, string lastName);
}
class ConcreteBuilder: IBuilder
{
string build(string firstName, string lastName)
{
return string.format("sir {0} {1}", firstName, lastName)
}
class Person
{
private string _firstName;
private string _secondName;
public Greetings(IBuilder builder)
{
return builder.build(_firstName, _secondName);
}
}
..
person = new Person();
builder = new ConcreteBuilder()
string greetings = person.Greetings(builder)
struct Person
{
string _firstName;
string _lastName;
}
string greetings1(Person person) {...}
string greetings2(Person person) {...}
Ну это чистое ООП без всяких нарушений.
Есть принцип OCP, который гласит, что классы должны быть закрыты для модификации, но открыты для расширения.
SomeClass c = new SomeClass();
c.SetValue1(1);
c.SetValue2(2);
c.DoSomeWork();
Some languages like Smalltalk and Ruby only allow access via object methods
Смотрите на инкапсуляцию как «пользователь» класса, а не как его «создатель», возможно это внесет ясность
С точки зрения «создателя» вас просто гложет то, что у вас «лишний» метод там, где он не нужен, а значит вы слишком рано начинаете думать об оптимизации и ставите ее выше поддержки\изменяемости кода.
Раньше я любит использовать field
Если рассматривать с точки зрения пользователя, понятие «инкапсуляция» становится бесполезным
Вы знаете, когда Кнут говорил «Преждевременная оптимизация — корень всех зол»
Я имел ввиду, что автор думает о том, что методы get\set внутри реализован вот так то (что как бы плохо), поэтому и надо посмотреть как пользователь — тогда тебе не важно что там внутри.
class Mailer {
SendMail(User CurrentUser) {
full_email = '"' + CurrentUser.getName() + '" <' + CurrentUser.getEmail() + '>'
...
}
}
То что foo.getName() формально нарушает принцип инкапсуляции точно также как и foo.name — это очевидный факт.
Если атрибут связан с внутренней реализацией, то есть класс-реализация изнутри взаимодействует со своим атрибутом, значит часть внутренней реализации открыта, то есть нарушена инкапсуляция по определению(см. ссылку на вики выше).
Нет, это не инкапсуляция. Это подтиповой полиморфизм. Почтитайте, пожалуйста, повнимательнее ссылку на Википедию, которую я вам дал.
Как это не фиксирует?
Нет, инкапсуляция к этому не имеет отношения. lair, извините, мне кажется вы просто не понимаете что значит инкапсуляция. Я даже ссылку вам с Вики привел с формальным определением, но вы все равно продолжаете называть «инкапсуляцией» вещи, которые никакого отношения к ней не имеют.
In a programming language, encapsulation is used to refer to one of two related but distinct notions, and sometimes to the combination thereof:
— A language mechanism for restricting access to some of the object's components.
— A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.
Если класс уже ушел в продакшн, то уже ничего не поменяешь
А если и поменяешь — это будет другой класс, другой релиз.
Что вы вкладываете в понятие «доступ»?
Если обсуждаемый пример заменить на другой, то нечего и обсуждать.
сокрытие реализации означает запрет доступа к состоянию объекта
А вот если вы «от балды» делаете геттеры и сеттеры, позволяя объектам извне «вручную» менять состояние этого объекта, то это уже нифига не инкапсуляция.
Name getName()
{
nameHistory.GetByDate(CurrentDate());
}
Name getName()
{
return name;
}
А вот наличие сеттера дает возможность достучаться пользователю напрямую к внутренности класса.
Да и откуда Вы знаете, что там именно указатель используется, а не индекс в таблице сущностей?
А в чём по Вашему разница в полиморфизмах? Чем один столь существенно отличается от другого, что Вы предлагаете говорить о разных сущностях и случайном совпадении названий?
class Амбал (Человек)
def разбить (Хрупкий предмет)
return предмет.ударить (об=я.найти (твёрдая поверхность), сила=100500)
в любой реализации, из которой вынимают фундамент, будет подобный хаос, независимо от парадигмы.
Так речь же не о фундаменте, а об изменении поведения всего лишь одного поля.
написать новый проект, в котором хотелось бы использовать уже готовые, протестированные наработки
Почему изменение поведения 5% записей должно вести к коренной переделке программы?
fig.stretchX(2).stretchY(2);
Круг — это не отдельная независимая сущность, а лишь частный случай возможного состояния эллипса.
возврат объекта другого класса — тоже нетривиальная задача, если нужно соблюсти принцип гласящий, что код не должен знать о всех возможных реализациях интерфейса, но только сам интерфейс.
Более того, объектно-ориентированные языки сами зачастую нарушают правило инкапсуляции, предоставляя доступ к данным через специальные методы — getters и setters в Java, properties в C# и т.д.
Так какие же дополнительные средства абстрагирования несёт в себе ООП? Понятия не имею. Выделение кода в подрограммы? Это умеет любой высокоуровневый язык. Объединение подпрограмм в одном месте? Для этого достаточно модулей. Типизация? Она была задолго до ООП.
Например, абстракция «база данных», скрывающая низкоуровневую реализацию, и позволяющая работать с разными базами данных через единый интерфейс (достаточно будет, например, просто указать нужный «драйвер»).
f = fopen("filename", "rw");
Заметьте, это все сделано на чистом C, без классов.
Первое — ваше, и мне оно не нравится, т.к. не понятно, чем тогда инкапсуляция отличается от, собственно, объекта.
Википедия даёт 2 определения того, что такое инкапсуляция. Первое — ваше, и мне оно не нравится, т.к. не понятно, чем тогда инкапсуляция отличается от, собственно, объекта.
Я имею ввиду, что инкапсуляция — это, по первому определению, связывание данных и методов; объект — это как раз получившаяся связка.
Не совсем верно. АТД по определению покрывает именно типы данных, понятие абстракции гораздо шире. Почитайте SICP: там как раз первые две главы описывают абстракцию по средствам процедур и по средствам данных.
Возможность использования единого интерфейса для работы с разными БД — это конкретно полиморфизм, он там на пару пунктов ниже идёт.
Инкапсуляция в данном случае — когда вы оперируете не напрямую с данными, а со свойствами объекта.
Зачем выделять их особенно для ООП — непонятно.
Используется более общий, «абстрактный» интерфейс для работы с БД, а более специфичная реализация сокрыта. Чем не пример абстракции? А уж используется ли тут полиморфизм — менее значимо.
public class SuitList
{
private ArrayList SuitArray = new ArrayList();
public bool Add(Suit argSuit)
{
if (argSuit.IsSuit(argSuit) == false)
{
return false;
}
SuitArray.Add(argSuit);
return true;
}
public Suit GetItem(int Index)
{
return SuitArray[Index] as Suit;
}
}
public abstract class Suit
{
public bool IsSuit(Suit argSuit)
{
bool retValue = true;
spades locSuit1 = argSuit as spades;
hearts locSuit2 = argSuit as hearts;
diamonds locSuit3 = argSuit as diamonds;
clubs locSuit4 = argSuit as clubs;
if (locSuit1 == null && locSuit2 == null && locSuit3 == null && locSuit4 == null)
{ retValue = false; }
return retValue;
}
}
public sealed class spades : Suit //(♠)
{}
public sealed class hearts : Suit //(♥)
{}
public sealed class diamonds : Suit // (♦)
{}
public sealed class clubs : Suit // (♣)
{ }
public Suit this[int Index]
{
get
{
return SuitArray[Index] as Suit;
}
}
data Suit = Spades | Hearts | Diamonds | Clubs
data Color = Black | White | LightGrey | RGB Int Int Int
...
doSome :: Color -> Whatever
doSome color = ...
...
doSome Grey
...
doSome Black
...
doSome (RGB 125 0 0)
public abstract class Suit
{
internal Suit() { }
}
public sealed class spades : Suit //(♠)
{ }
public sealed class hearts : Suit //(♥)
{ }
public sealed class diamonds : Suit // (♦)
{ }
public sealed class clubs : Suit // (♣)
{ }
// В другой сборке
public sealed class NoSuit : Suit { }
// ошибка CS0143: Для типа "Suit" не определен конструктор
это моя добрая воля вызывать конструктор базового класса или нет
if (locSuit1 == null && locSuit2 == null && locSuit3 == null && locSuit4 == null)
Я лично не понял тему про 95% кода в каком-то стиле. Если ООП не подходит под ваше описание технологии — это значит, что проблемы в ООП, а не в описании?
Если большая часть вашего кода по факту написана в процедурном стиле (данные, методы, объекты пораждаются в основном для выполнения каких то действией), а ООП-шные фишечки (хотя бы те же наследование, полиморфизм и т.д.) используются относительно редко, то мне непонятно, почему в общем и целом это называется ООППо факту это модульное программирование. От ООП отличается только отсутствием неявного аргумента
this</e>;-).Более того, объектно-ориентированные языки сами зачастую нарушают правило инкапсуляции, предоставляя доступ к данным через специальные методы — getters и setters в Java, properties в C# и т.д.
Конец файла — это в конец класса? Если метод логически не принадлежит классу, то и не должен в нём находиться, он должен нахидться просто недалеко от места использования. Чтобы и логично, и далеко за ним лазить не пришлось.
Это непринято не просто так. Такие языки как Java плохо поддерживают статические методы, дискреминируя их по сравнению с виртуальными. Например, статические методы нельзя объявить в интерфейсе, а это значит, что если мне нужно работать с двумя базами данных через единый интерфейс, мне _придётся_ сделать эти методы виртуальными и создать для них объекты.
Я пробовал писать на ОО языках код по-другому. Много пробовал. И нашёл ооочень много граблей, мешающих сменить парадигму.
В итоге получается, что любое решение поставленной вами задачи будет использовать ООП, независимо от того, на каком языке вы ее решите — C#, Java, чистый C, ассемблер или Haskell.
Как вы вообще представляете виртуальный статический метод?
puts self.inspect
puts self.class.inspect
В таком случае любой язык — ООП язык? В том то и фишка, что ООП присвоил эти понятия, хотя они являются общими для всех языков.
struct some_interface {
virtual void some_method() = 0;
};
struct derived : some_interface {
void some_method();
};
//...
some_interface* obj = new derived();
//...
obj->some_method();
struct some_interface {
void (*some_method)(some_interface*);
};
struct derived {
some_interface some_interface_inst;
};
//...
derived* dd = malloc(sizeof(derived));
dd->some_interface_inst->some_method = derived_some_method_impl;
some_interface* obj = &dd->some_interface_inst;
//...
(*(obj->some_method))(obj);
typedef int (*behavior_t)(char);
typedef struct {
int a;
int b;
behavior_t doSomething;
} foo;
void setA(foo*, int);
int getA(foo*);
void setB(foo*, int);
int getB(foo*);
void init(foo* f, int a, int b, behavior_t behavior);
//Наследование
void bar(foo* f, int a, int b) {
behavior_t behavior = 0;
init(f, a, b, behavior);
}
polymorphic_call(foo*);
import abc
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
@abc.abstractmethod
def doSomething(self, c):
pass
interface Foo {
int a;
int b;
int doSomething(char c);
}
Вот вы сказали «трюки». Да, Java трюки не разрешает. Java — серьезный язык программирования со статической типизацией. Java использует не трюки, а паттерны проектирования.
А во-вторых, понятия тоже никто не присваивал. До появление концепции ООП этих понятий попросту не существовало
Это совершенно не означает, что любая программа, написанная на ОО-языках, использует концепцию ООП.
public static final MyModule instance = new MyModule();
GTK+ написана на языке Си, но тем не менее, является объектно-ориентированной[9]© Википедия
struct GObjectClass {
GTypeClass g_type_class;
...
void (*set_property) (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
...
}
...
g_object_set_property(G_OBJECT(session), pspec->name, &value);
Я не умею программировать на объектно-ориентированных языках. Не научился. После 5 лет промышленного программирования на Java я всё ещё не знаю, как создать хорошую систему в объектно-ориентированном стиле. Просто не понимаю.На этом стоило бы статью и закончить. Sad but true.
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:app_urls]] success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.apps = [[JSON objectForKey:@"feed"] objectForKey:@"entry"];
[self.tableView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
//
}];
Чтобы сделать один HTTP запрос мне нужно создать объект типа URL, затем объект типа HttpConnection, затем объект типа Request… ну, вы поняли.
Суть ООП это именно возможность совершать определённые вызовы, которые используют некую структуру данных, отображающую состояние какой-либо сущности.
struct Person {
char* name;
int weight;
int height;
};
int foo(Person p) {
// ...
}
Принципы SOLID никакого концептуального значения не имеют — это чисто ОО паттерны и за пределами ООП полностью теряют смысл.
Ну попробуйте описать как применить LSP без полиморфизма.
Там не предполагается что процедуры будут как то расширятся.
Какой смысл имеет SRP без понятия объекта, на котором может быть ответственность (ну для функций и процедур его притянув за уши можно применить — но там он не нужен).
То есть он работает в модульных архитектурах — но сам принцип там не особо нужен — всместо него есть базовые принципы организации зависимостей.
Вы спрашиваете, что отличает ООП от других? Да объекты же! Абстрактные типы данных, инкапсулированные, унаследованые, полиморфные, неважно. Принцип в том, что объекты представляют тесно связанный модуль, который хорошо решает свою задачу.
А вы не задумывались что поток, протокол или скажем сценарий тоже есть объекты? Которые обладают свойствами и поведением.
Т.е. процесс — объект который содержит состояние (на каком шаге сейчас, какие шаги могут быть и т.д.) и поведение (перейти на другой шаг, откатиться на начало и т.д.).
«Именно поэтому процессы даже отображаются иными диаграммами, нежели объекты.» — а как таковой диаграммы объектов нет.
почему по вашему подобная абстракция процесса не решает задачу?
Т.е. при проектировании системы, реализующей этот бизнес процесс вы (или точнее я) все равно буду рассматривать это как вызов методов и изменение состояния объектов моей системы. Понимаете?
А вы не задумывались что поток, протокол или скажем сценарий тоже есть объекты? Которые обладают свойствами и поведением. Которые взаимодействуют с другими объектами.
Это гораздо более чем просто надстройка на процедурным программированием. Это изменение восприятия кода и элементов программы. Это объектно-абстрактное мышление. Это совсем другое, нежели процедурных подход.
ООП — это парадигма, которая говорит нам программировать/проектировать используя объекты и взаимодействия между ними.
Я говорю что геттеры и сеттеры это инструмент, который помогает в реализации инкапсуляции. Вы вообще понимаете чего я пытаюсь сказать?
вы что подразумеваете под трогать внутренности? И что значит что инкапсуляция запрещает трогать внутренности? И кто вам, блять, сказал что в пайтоне нереализуема инкапсуляция?
foreach (var shape in scene)
{
shape.Show();
}
Систему на много проще проектировать в контексте объектов (а не данных и методов, которые будут их обрабатывать).
В конце концов Вы все переводите в объекты (классы), потому как это дает возможность делегировать обязанности на определенные логические и структурированные части кода
К сожалению не знаю что такое декларативный DSL, но кто-то же его выполняет, переводит в другую структуру за Вас (предположу что этот уровень абстракции выше нежели ООП).
Систему на много проще проектировать в контексте объектов
А статью считаю бредовой отчасти, такое ощущение что у автора накипело просто.
Чтобы сделать один HTTP запрос мне нужно создать объект типа URL, затем объект типа HttpConnection, затем объект типа Request… ну, вы поняли.
using(var conn = new SqlConnection(connString))
{
/* повторяем 100500 раз */
using (var cmd = conn.CreateCommand())
{
cmd.Execute()
}
}
/* повторяем 100500 раз */
sql_cmd_execute(cmdText, connString);
string connetionString = null;
SqlConnection cnn ;
SqlCommand cmd ;
string sql = null;
SqlDataReader reader ;
connetionString = "Data Source=ServerName;Initial Catalog=DatabaseName;User ID=UserName;Password=Password";
sql = "Your SQL Statement Here , like Select * from product";
cnn = new SqlConnection(connetionString);
try
{
cnn.Open();
cmd = new SqlCommand(sql, cnn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
MessageBox.Show(reader.GetValue(0) + " - " + reader.GetValue(1) + " - " + reader.GetValue(2));
}
reader.Close();
cmd.Dispose();
cnn.Close();
}
catch (Exception ex)
{
MessageBox.Show("Can not open connection ! ");
}
var query string;
// connect to the database using the information defined above
db := mysql.Connect(hostname, username, password, database);
db.SelectDb("gotest");
// run an update query
query = "UPDATE `gotest` SET `testfield` = 'Update something'";
fmt.Println("Executing query: ", query);
db.Query(query);
// if the query was successful, view some information
fmt.Println("Affected rows: ", db.AffectedRows, "InsertId: ", db.InsertId, "\n");
// run an insert query
query = "INSERT INTO `gotest` SET `testfield` = 'Insert something', `testfield2` = 12345.123, `testfield3` = NOW()";
db.Query(query);
fmt.Println("Executing query: ", query);
// if the query was successful, view some information
fmt.Println("Affected rows:", db.AffectedRows, "InsertId:", db.InsertId, "\n");
query = "SELECT * FROM `gotest`";
db.Query(query);
fmt.Println("Executing query: ", query);
fmt.Println("Num rows: ", db.NumRows());
for {
row := db.FetchRow();
if row == nil {
break
}
fmt.Printf("(%T) %d => (%T) %s, (%T) %f, (%T) %+v\n", row[0], row[0], row[1], row[1], row[2], row[2], row[3], row[3]);
}
// close the connection
db.Close();
И часто вы 100500 раз в цикле обращаетесь к БД?
db — это структура, а не объект, в том то и дело. Т.е. хранится на стеке, после использования автоматически зачистится (если больше не нужен, конечно).
Эмм. А вы понимаете, да, что то, где хранится объект, к ООП никакого отношения не имеет?
Эффективные программы используют мало памятиЭффективные проекты требуют мало ресурсов на их поддержку.
Эффективные проекты требуют мало ресурсов на их поддержку.
Преждевременная оптимизация — корень всех бед. // Тони Хоар
Простота — дух эффективности. // A. Freeman
ОО способ — добавить ToNumber в string. См смолток и extension methods в C#
Непонятно почему добавление простого класса это плохо. Анонимные типы не противоречат ООП.
Пробовали ли вы подсчитать, сколько байтов занимает каждый такой объект?
Стек — это тоже память.
anonymous f()
{
return {name:"s";value:"v"};
}
BigSTructure structure;
very_long_function(structure)
void very_long_function(BigSTructure &s)
{
send_structure(s);
// начиная отсюда s - мусор потому, точ не используется
long_running_code();
}
msdn.microsoft.com/en-us/library/bb397696.aspx
Никто не мешает создавать поменьше реквестов. К тому же посмотрите на любой современный язык — там сборка мусора, а в хаскеле к тому же ленивость. С другой стороны, к ващшим услугам C++ и object pascal без GC.
structure будет висеть пока не закончится very_long_function();
Там с объектами/структурами вообще интересно: компилятор сам решает, где разместить структуру. По возможности размещает на стеке, если объект используется вне функции или просто очень большой, то на хипе.
Люди->ВыбратьЧеловека('Вася')->ОтправитьЗаВодкой()Люди->ВыбратьЧеловека('Вася')->ОтправитьЗаВодкой()
(отправить-за "водка" (выбрать :имя "Вася" (все-пиплы)))Проблема в том что автор не хочет принять ООП.Видимо, это больше проблема ООП, чем автора (:
Функции просто и легко, с ооп нужно быть на два шага впереди, зато в итоге работы уменьшиться.Это если использовать не «функции», а скорее «процедуры».
Расскажете, как в процедурном или функциональном подходе создать обобщенный «выгуливающий» метод для «домашних животных»?
struct Animal {
void (*walk)() = NULL;
} dog, cat, giraffe;
...
dog->walk();
cat->walk();
giraffe->walk();
type Animal = Cat | Dog | Giraffe
walk Cat = ...
walk Dog = ...
walk Giraffe = ...
struct Animal {
void (*walkMe)(Animal a) = NULL;
} dog, cat, giraffe;
...
void walk(Animal a) {
a->walk(a);
}
Я не знаю ООП