Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

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

87
27 января 2011 года
Kogrom
2.7K / / 02.02.2008
Уже обсуждали циклы, шаблоны. Возможно, кому-то будет интересна тема инкапсуляции. Тут я буду говорить именно о той, которая определяется синтаксисом, ключевыми словами типа private, protected и т.п. Кто что про неё думает? Нужна ли она вообще?

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

Но и с данными должна быть некая условная инкапсуляция. То есть должен быть не полный запрет, а генерирование предупреждений компилятором (интерпретатором) в случае их использования. Такой подход может пригодиться при рефакторингах.
Страницы:
6
03 февраля 2011 года
George
4.1K / / 05.01.2007
Цитата: Нездешний
Широко известная в узких кругах модель обучения ;)


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

241
03 февраля 2011 года
Sanila_san
1.6K / / 07.06.2005
Цитата: Нездешний
Широко известная в узких кругах модель обучения ;)

Ненуачо, она ведь работает.

Кстати насчёт моделей обучения: я даже со своим аналитическим мышлением научился писать грамотно вовсе не потому, что учил правила. Хуже того, я даже как-то умудрился полностью успешно (30 из 30) сдать тест по русскому языку (на знание правил!). Но если попросить меня перечислить правила, которые я знаю, их едва ли наберётся больше десятка. Я, например, не знаю даже, что такое деепричастие. А пишу грамотно потому, что много читал в детстве, да и сейчас немало. Полагаю, я не один такой.

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

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

Ага, но есть вот какая фишка: по статистике в карьере водителя большинство аварий случается на этапе наезда 40-60 тысяч км, где-то между вторым и четвёртым годами водительской практики, смотря кто и как ездит. Между тем, поддерживать беседу и смотреть по сторонам водитель начинает очень быстро, в течение нескольких месяцев. Умение освобождать внимание от управления появляется быстро, а вот навык правильного распределения внимания нарабатывается многие месяцы, а то и годы. Умение правильно оценивать своё состояние за рулём тоже приходит далеко не сразу. Это гораздо более тонкие навыки. Так что действительное неосознанное знание приходит только спустя два-три года практики. С умением прогнозировать ситуацию ещё хуже, к кому-то оно вовсе не приходит.

87
03 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Sanila_san
Хотя таки да, если не обсуждать профессиональные темы, роста не будет. Другой вопрос, не зашло ли обсуждение в тупик? Не мне решать.:)



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

Другие не в теме, но мнение имеют. Это нормально.

Теперь ещё раз про практику. Алан Купер сравнил создание ПО со строительством башенки из кирпичей, с основанием в один кирпич. Чем выше ты собираешься строить башню, тем аккуратнее складываешь кирпичи. Тут возникают вопросы: можно ли их склеить? какие воздействия будут оказываться на башню? Нет ли тут землетрясений? и т.д.

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

Моделирование и прототипирование - это хороший приём при проектировании. Но тот, кто использует прототип вместо готовой программы ("а чё, дёшево же и быстро?") может разочароваться.

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

11
03 февраля 2011 года
oxotnik333
2.9K / / 03.08.2007
Когром, ты бы выложил здесь свои выводы по поводу обсуждаемой темы (инкапсуляции), в катце и самую суть, а то выставил всех (кроме неназванных 3-х человек) дураками. К стати, мне интересно было б почитать выводы.
87
03 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: oxotnik333
Когром, ты бы выложил здесь свои выводы по поводу обсуждаемой темы (инкапсуляции), в катце и самую суть



Ну так вот же:
http://forum.codenet.ru/showpost.php?p=343818&postcount=106

535
03 февраля 2011 года
Нездешний
537 / / 17.01.2008
На мой взгляд, код должен быть максимально прост для понимания. "Бесконечное разделение классов до элементарных объектов" зачастую этому критерию не соответствует.
Для выделения классов нужны веские причины. Возможное "когда-нибудь" повторное использование кода не является такой причиной. Раз уж мы заговорили о философии - можно вспомнить принцип бритвы Оккама: "Не множьте сущностей без надобности".
"Бесконечное разделение классов до элементарных объектов" зачастую не нужно, поскольку усложняет понимание кода, требует больше времени и усилий и не дает весомых преимуществ. Кажется, некий перфекционизм толкает тебя выделять новые классы, следуя абстрактной красивой модели. Сам же признаешь: [QUOTE=Kogrom]Понятно, что выделение класса требует больше усилий, чем использование модификатора доступа. И при недостатке времени их удобно использовать[/QUOTE]Но недостаток времени - он же всегда!
Показатель для меня лично здесь такой - если при проектировании структура кода уложилась в голове, не вызывает какого-то внутреннего дискомфорта - значит, дальше дробить не надо
535
03 февраля 2011 года
Нездешний
537 / / 17.01.2008
Вот для примера класс отрезка. Как и зачем тут избавиться от приватных методов, если они больше нигде не нужны сами по себе?
Контекст такой: приходит откуда-то последовательность точек по одной. Последовательность аппроксимировать прямой. Считать и выдавать конечные точки отрезка и угол наклона к оси абсцисс.
Усреднять будем таким методом: искать средние арифметические координат Х и У для всех точек последовательности (кроме первой) - таким образом найдем некую "усредненную" точку. Далее с помощью первой точки последовательности и "усредненной" точки найдем угол наклона прямой. И с помощью угла и максимального расстояния найдем конец отрезка

Всякие проверки и часть кода опущены
Код:
typedef std::list<POINT> ContainerPoints;

class CSegment
{
public:
    CSegment();
    void AppendPoint(const POINT&);
    double GetAngleRadians() const;
    POINT GetStartPoint() const;
    POINT GetEndPoint();
    ContainerPoints GetPoints();
private:
    double sumX;
    double sumY;
    double angleRadians;
    ContainerPoints contPoints;
   
    void CountAngle();
    double Distance(const POINT&, const POINT&);
};

void CSegment::AppendPoint(const POINT& pt)
{
    contPoints.push_back(pt);
    sumX += pt.x;
    sumY += pt.Y;
    CountAngle();
}

double CSegment::GetAngleRadians() const
{
    return angleRadians;
}
   
POINT CSegment::GetStartPoint()
{
    return contPoints.front();
}

POINT GetEndPoint()
{
    //найдем макс. расстояние между точками для определения длины отрезка
    double distanceMax = 0;
    for (ContainerPoints::iterator it = contPoints.begin(); it != contPoints.end(); ++it)
    {
        double distanceCurrent = Distance(contPoints.front(), *it);
        if (distanceMax < distanceCurrent)  distanceMax = distanceCurrent;
    }
   
    CountAngle();
   
    //дальше ищем конечную точку, исходя из системы уравнений
    //y = kx + b, где k = tg(angleRadians)
    //x*x + y*y = distanceMax*distanceMax; 
   
}

double CountAngle()
{
    double midX = sumX / (contPoints.size() - 1);
    double midY = sumY / (contPoints.size() - 1);
    angleRadians = atan2(midY - contPoints.front().y, midX - contPoints.front().x);
}
87
03 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
Вот для примера класс отрезка. Как и зачем тут избавиться от приватных методов, если они больше нигде не нужны сами по себе?


Посмотрим на открытые методы. AppendPoint "запускает ракету". Зачем он что-то там считает, когда его обязанность записать точку в контейнер? Мы не знаем, запросит у нас кто-то угол или нет, но рассчитываем его при добавлении каждой точки. И т.д.

Вообще, обязанность класса CSegment, определяемая его интерфейсом, - складировать точки и выдавать некие расчёты. Вести их он не обязан. Хранить какие-то промежуточные данные - тоже. Потому черновик переделки примерно такой:

Код:
typedef std::list<POINT> ContainerPoints;


double CountAngle(const POINT &p1, const POINT &p2)
{
    return atan2(p2.y - p1.y, p2.x - p1.x);
}

double Distance(const POINT&, const POINT&){...}

POINT GetMiddle(const ContainerPoints &points){...}

class CSegment
{
public:
    CSegment();
    void AppendPoint(const POINT&);
    double GetAngleRadians() const;
    POINT GetStartPoint() const;
    POINT GetEndPoint();
    ContainerPoints GetPoints();
private:
    ContainerPoints contPoints;
};

void CSegment::AppendPoint(const POINT& pt)
{
    contPoints.push_back(pt);
}

double CSegment::GetAngleRadians() const
{
    return CountAngle(contPoints.front(),  GetMiddle(contPoints));
}
   
POINT CSegment::GetStartPoint()
{
    return contPoints.front();
}

POINT CSegment::GetEndPoint()
{
    //найдем макс. расстояние между точками для определения длины отрезка
    double distanceMax = 0;
    for (ContainerPoints::iterator it = contPoints.begin(); it != contPoints.end(); ++it)
    {
        double distanceCurrent = Distance(contPoints.front(), *it);
        if (distanceMax < distanceCurrent)    distanceMax = distanceCurrent;
    }
   
    angleRadians = GetAngleRadians();
   
    //дальше ищем конечную точку, исходя из системы уравнений
    //y = kx + b, где k = tg(angleRadians)
    //x*x + y*y = distanceMax*distanceMax;    
   
}

Теперь некоторые методы не принадлежат классу. Это плохо? С чего бы?
87
03 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Если кто-то думает, что я еретик, то почитайте Страуструпа про функции-помощники (Язык программирования C++, специальное издание, стр. 287). Он пишет:

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

535
03 февраля 2011 года
Нездешний
537 / / 17.01.2008
И теперь эти методы видны отдельно от класса. Зачем? Какие преимущества?

ЗЫ
Случай из практики. Задание - максимально быстро и с минимум переделок "свести" вместе два приложения в одно. Приложения для общения с железкой, одно - для старой версии железки, другое - для новой. Сделано там было, как ты предложил - вместо приватных методов просто функции.

Как нетрудно догадаться, в этих двух приложениях были функции с одинаковыми именами (реализации отличались). Объявлены они были в разных cpp, хедеры нигде друг на друга не ссылались.
Т.е. что-то вроде
Код:
//file1.cpp
double sum(double a, double b)
{
     return a + b;
}

void Class1::SomeClassMethod()
{
    ...
    sum(x, y);
    ...
}

//file2.cpp
double sum(double a, double b)
{
     return a * b;
}

void Class2::SomeClassMethod()
{
    ...
    sum(x, y);
    ...
}
Можешь себе представить мое удивление, когда после продолжительной отладки выяснилось, что линкер (borland) собрал программу так, что Class2::SomeClassMethod использовал внутри себя функцию sum из file1.cpp!!!

Пришлось плясать вокруг них с namespace'ми
3
03 февраля 2011 года
Green
4.8K / / 20.01.2000
Цитата: Kogrom
Если кто-то думает, что я еретик, то почитайте Страуструпа про функции-помощники (Язык программирования C++, специальное издание, стр. 287). Он пишет:


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

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

В приведенной цитате я не нашел ни про тестирование, ни про обязательную универсальность.

5
03 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Нездешний

Пришлось плясать вокруг них с namespace'ми


Наверно мой мозг съеден .NET-ом, но почему нельзя было сразу использовать пространства имен? :rolleyes:

535
03 февраля 2011 года
Нездешний
537 / / 17.01.2008
К тому же, заметь, ты вынес расчет средней точки из класса, и избавился от промежуточного суммирования и приватных членов, хранящих эти суммы. Собственно, именно это и позволило тебе вынести расчет за класс.

Но зато тебе теперь нужно каждый раз для расчета средней точки прогонять весь контейнер для суммирования. А если точек много и нужно максимальное быстродействие?
535
03 февраля 2011 года
Нездешний
537 / / 17.01.2008
Цитата: hardcase
Наверно мой мозг съеден .NET-ом, но почему нельзя было сразу использовать пространства имен? :rolleyes:



Для меня подобный фокус оказался сюрпризом! Повторю, модули друг на друга не ссылались, и вообще не знали друг о друге. Т.е. Class2 не знал о существовании функции sum в file1.cpp
Иначе бы я при компиляции получил сообщение о redefinition. Но все было тихо

87
03 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
ЗЫ
Случай из практики. Задание - максимально быстро и с минимум переделок "свести" вместе два приложения в одно. Приложения для общения с железкой, одно - для старой версии железки, другое - для новой. Сделано там было, как ты предложил - вместо приватных методов просто функции.


Неймспейсы же есть. Зачем на класс взваливать обязанность неймспейса, если они отдельно могут существовать?

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



Ну нет. "Матрёшечность" - это не мой термин. Главное - постараться исключить приватные методы за счёт использования объектов. А функцию вполне можно считать объектом, у которого один метод и нет полей.

87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
К тому же, заметь, ты вынес расчет средней точки из класса, и избавился от промежуточного суммирования и приватных членов, хранящих эти суммы. Собственно, именно это и позволило тебе вынести расчет за класс.

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


Я действовал из этого принципа:

Цитата: Нездешний
На мой взгляд, код должен быть максимально прост для понимания.


Думаю, что он стал проще.

535
04 февраля 2011 года
Нездешний
537 / / 17.01.2008
Цитата: Kogrom
Зачем на класс взваливать обязанность неймспейса

Ему не тяжело ;) И класс УЖЕ есть.

А зачем городить впридачу отдельно неймспейс с вынесенными методами? Зачем мне эти методы отдельно? Какая цель этого? Только возможные тесты?

535
04 февраля 2011 года
Нездешний
537 / / 17.01.2008
Цитата: Kogrom
Думаю, что он стал проще.

Но свои задачи он должен при этом все равно выполнять! Угол, кстати, запрашивается после добавления каждой точки. Суммирование всего контейнера каждый раз, соответственно, неприемлемо :)
Т.е. нужно где-то хранить промежуточные результаты суммирования. Самое логичное - в приватных членах класса. Таким образом, функция подсчета средней точки требует доступа к приватным членам класса. Будешь передавать их по ссылке или указателю через параметры функции?

87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
А зачем городить впридачу отдельно неймспейс с вынесенными методами? Зачем мне эти методы отдельно? Какая цель этого? Только возможные тесты?



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

А тесты "белого ящика" - это отдельная тема. Меня пока интересуют "характеристические тесты", ибо пока сам не осилил метод "вначале тесты".

5
04 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Сдается мне, дорогой Когром, ты не уловил одной простой мысли.
Ремесло программирования тесно связано с самоограничением - ограничивая себя мы избавляемся от досадных ошибок и лучше видим путь по которому движемся, разрабатывая софт. Тесты - это неплохой способ поставить ограничения, польза их всем очевидна (возможно даже и преувеличена). Статическая типизация - другой способ ограничений. Так вот модификаторы - это еще один эшелон ограничений, мы декларируем, что приватные члены не будут использоваться нигде кроме класса, в котором они объявлены. Тем самым мы сузили их потенциальную область использования - мы ограничили область кода, которая может потенциально зависить от этих членов. Отсюда напрашивается простой вывод: модификаторы доступа помогают понижать сложность поддержки кода.
535
04 февраля 2011 года
Нездешний
537 / / 17.01.2008
Т.е. кроме тестов, причина только одна - возможное когда-нибудь повторное использование тех функций

А про еретиков - это ты как-то круто загнул! Возможно, мы иногда излишне горячны, но на личности переходить не было никакого намерения. Вся наша горячность относится только к теме дискуссии, ни коим образом не затрагивая самих участвующих.
87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
Но свои задачи он должен при этом все равно выполнять! Угол, кстати, запрашивается после добавления каждой точки. Суммирование всего контейнера каждый раз, соответственно, неприемлемо :)
Т.е. нужно где-то хранить промежуточные результаты суммирования. Самое логичное - в приватных членах класса. Таким образом, функция подсчета средней точки требует доступа к приватным членам класса. Будешь передавать их по ссылке или указателю через параметры функции?


Ну и храни суммарную точку тогда. В чём проблема передать её и размер контейнера?

87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
А про еретиков - это ты как-то круто загнул! Возможно, мы иногда излишне горячны, но на личности переходить не было никакого намерения.


Это была ссылка на одно из сообщений Green-а.
Ок. Вы все правы, а я спать.

535
04 февраля 2011 года
Нездешний
537 / / 17.01.2008
Цитата: Kogrom
Ну и храни суммарную точку тогда. В чём проблема передать её и размер контейнера?

И кому вне класса нужна будет функция подсчета угла с таким специфическим набором параметров?

6
04 февраля 2011 года
George
4.1K / / 05.01.2007
Оффтоп:
Kogrom, про еретика шутка была, ты разве не заметил?
87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
И кому вне класса нужна будет функция подсчета угла с таким специфическим набором параметров?



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

Код:
typedef std::list<POINT> ContainerPoints;

double CountAngle(const POINT &p1, const POINT &p2)
{
    return atan2(p2.y - p1.y, p2.x - p1.x);
}

double Distance(const POINT&, const POINT&){...}


class CSegment
{
public:
    CSegment();
    void AppendPoint(const POINT&);
    double GetAngleRadians() const;
    POINT GetStartPoint() const;
    POINT GetEndPoint();
    ContainerPoints GetPoints();
private:
    ContainerPoints contPoints;
    SummPoint sumPoint;
};

void CSegment::AppendPoint(const POINT& pt)
{
    contPoints.push_back(pt);
    sumPoint.append(pt);
}

double CSegment::GetAngleRadians() const
{
    return CountAngle(contPoints.front(),  sumPoint.GetMiddle(contPoints.size()));
}
   
POINT CSegment::GetStartPoint()
{
    return contPoints.front();
}

POINT CSegment::GetEndPoint()
{
    //найдем макс. расстояние между точками для определения длины отрезка
    double distanceMax = 0;
    for (ContainerPoints::iterator it = contPoints.begin(); it != contPoints.end(); ++it)
    {
        double distanceCurrent = Distance(contPoints.front(), *it);
        if (distanceMax < distanceCurrent)    distanceMax = distanceCurrent;
    }
   
    angleRadians = GetAngleRadians();
   
    //дальше ищем конечную точку, исходя из системы уравнений
    //y = kx + b, где k = tg(angleRadians)
    //x*x + y*y = distanceMax*distanceMax;    
   
}

И вот мы дошли до агрегированного объекта...
Кстати, отдельно можно поговорить о профилировании и преждевременной оптимизации :)

На счёт еретика - это шутка с долей шутки.
87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: hardcase
Отсюда напрашивается простой вывод: модификаторы доступа помогают понижать сложность поддержки кода.


Я вижу другую простую вещь: модификаторы доступа, применяемые для методов, обычно выявляют плохую архитектуру. Единственный пример их оправданного использования - синглтоны. Но это спорный пример, ибо многие опытные программисты (Кент Бек, Green) утверждают, что синглтон не нужен.

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

5
04 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Kogrom
Я вижу другую простую вещь: модификаторы доступа, применяемые для методов, обычно выявляют плохую архитектуру.

Обычно? Примеры плохих архитектур в студию!

5
04 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Kogrom
Я вижу другую простую вещь: модификаторы доступа, применяемые для методов, обычно выявляют плохую архитектуру.



Вот тебе пример некоторого класса:

Код:
public sealed class GlossaryProcessor
{
    public GlossaryProcessor(DiContainer container, Language srcLang, Language destLang, int parallelDegree)
    {
        this._container = container;
        this._srcLang = srcLang;
        this._destLang = destLang;
        this._parallelDegree = parallelDegree;
        this._sharedDataManager = container.Resolve<SharedDataManager>();
        this._unitWeightProvider = new SearchUnitWeightProvider(container.Resolve<TMEngineSearcher>(), container.Resolve<ILogWriter>());
        this._config = container.Resolve<Config>();
        this._logWriter = container.Resolve<ILogWriter>();
        this._translationsDataManager = container.Resolve<TranslationsDataManager>();
    }

    public void Run(string fileName)
    {
        using (var stream = new FileStream(fileName, FileMode.Create))
        using (var xmlWriter = new XmlTextWriter(stream, Encoding.UTF8))
        {
            xmlWriter.Formatting = Formatting.Indented;
            xmlWriter.WriteStartDocument();
            xmlWriter.WriteStartElement("root");

            _logWriter.Write(string.Format("Loading glossary items {0} - {1}...", _srcLang.CultureName, _destLang.CultureName));

            var pageNumber = 0;
            var totalItems = 0;
            var itemsCount = 0;
            do
            {
                var items = queryPage(++pageNumber, out totalItems);
                if (pageNumber == 1)
                    _logWriter.Write(string.Format("{0} items found for {1} - {2}", totalItems, _srcLang.CultureName, _destLang.CultureName));
                processPage(xmlWriter, items, itemsCount);
                itemsCount += items.Count();
            } while (itemsCount < totalItems);

            xmlWriter.WriteEndElement();
        }
    }

    private IEnumerable<TextsPair> queryPage(int pageNumber, out int totalItems)
    { /* тут был закомментированный кусок кода использовавшийся для отладки */
        return _translationsDataManager.SelectGlossaryPairs(_srcLang, _destLang, pageNumber, _config.GlossaryPageSize, out totalItems, _config.SqlCommandTimeout);
    }

    private void processPage(XmlWriter xmlWriter, IEnumerable<TextsPair> items, int itemsProcessed)
    {
        var unitsWeights = items
            .AsParallel()
            .WithDegreeOfParallelism(_parallelDegree)
            .WithExecutionMode(ParallelExecutionMode.ForceParallelism)
            .WithMergeOptions(ParallelMergeOptions.NotBuffered)
            .Select((item, selectIndex) =>
            {
                SharedDataManager.Current = _sharedDataManager;

                var itemIndex = itemsProcessed + selectIndex;
                var weight = _unitWeightProvider.GetWeight(item.Text1, item.Text2, _srcLang, _destLang);

                lock (xmlWriter)
                {
                    xmlWriter.WriteStartElement("item");
                    xmlWriter.WriteAttributeString("txt1", item.Text1);
                    xmlWriter.WriteAttributeString("txt2", item.Text2);
                    xmlWriter.WriteAttributeString("count", weight.ToString());
                    xmlWriter.WriteEndElement();
                }

                _logWriter.Write("Item #" + itemIndex + ": \"" + item.Text1 + "\" - \"" + item.Text2 + "\" - " + weight);

                return Tuple.Create(item.UnitID.GetValueOrDefault(), weight);
            });

        _translationsDataManager.SaveUnitsWeights(unitsWeights);
    }

    private readonly DiContainer _container;
    private readonly int _parallelDegree;
    private readonly SharedDataManager _sharedDataManager;
    private readonly IUnitWeightProvider _unitWeightProvider;
    private readonly Language _srcLang;
    private readonly Language _destLang;
    private readonly Config _config;
    private readonly ILogWriter _logWriter;
    private readonly TranslationsDataManager _translationsDataManager;
}


Расскажи, где тут плохая архитектура и почему класс стоит переписать без private-методов.
87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: hardcase
Обычно? Примеры плохих архитектур в студию!


То есть пример от Нездешнего не подходит? Почему? Обидеть боишься? :)

А если не видишь недостатков в его примере, то и других приводить нет смысла.

87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: hardcase
Вот тебе пример некоторого класса:
...
Расскажи, где тут плохая архитектура и почему класс стоит переписать без private-методов.



Вот тебе и "Single responsibility principle"... Тут вам и 9 полей в одном классе, и длинные методы, и обращение к библиотечным средствам в классе, который оперирует высокоуровневыми понятиями.

Ладно, может я горячусь, может не вижу простых вещей. Но ты, как человек, имеющий опыт в тестировании интерфейсов с помощью юнит-тестов, расскажи, как будешь тестировать метод Run. Интересно послушать.

5
04 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Kogrom
Вот тебе и "Single responsibility principle"... Тут вам и 9 полей в одном классе, и длинные методы, и обращение к библиотечным средствам в классе, который оперирует высокоуровневыми понятиями.

Как корелирует количество полей и SRP?
Как ты оценил длину методов?
Что ты понимаешь под "обращение к библиотечным средствам"?

Цитата: Kogrom
как будешь тестировать метод Run. Интересно послушать.

Никак. Это не тот случай, где необходимы юнит тесты.
Я просто запущу эту утиллиту и посмотю чего она посчитает.

87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: hardcase
Как корелирует количество полей и SRP?


Расскажи мне назначение this._container, например.

Цитата: hardcase
Как ты оценил длину методов?


Оценил сколько параметров взаимодействуют в одном методе.

Цитата: hardcase
Что ты понимаешь под "обращение к библиотечным средствам"?


 
Код:
using (var stream = new FileStream(fileName, FileMode.Create))
using (var xmlWriter = new XmlTextWriter(stream, Encoding.UTF8))

Или FileStream и XmlTextWriter не являются библиотечными классами?
Цитата: hardcase
Никак. Это не тот случай, где необходимы юнит тесты.
Я просто запущу эту утиллиту и посмотю чего она посчитает.


Почему это не тот случай? Почему нельзя компьютеру поручить посмотреть чего и как она считает?

63
04 февраля 2011 года
Zorkus
2.6K / / 04.11.2006
Цитата: Kogrom
Я вижу другую простую вещь: модификаторы доступа, применяемые для методов, обычно выявляют плохую архитектуру. Единственный пример их оправданного использования - синглтоны. Но это спорный пример, ибо многие опытные программисты (Кент Бек, Green) утверждают, что синглтон не нужен.

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


Вротмненоги! Модификаторы доступа на уровне методов -> плохая архитектура?!

87
04 февраля 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Zorkus
Вротмненоги! Модификаторы доступа на уровне методов -> плохая архитектура?!


Докажи обратное - буду только рад. Пример приведи какой-нибудь :)

5
04 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Kogrom
Расскажи мне назначение this._container, например.

Возможно именно это поле нигде и не используется :)

На деле это DI-контейнер.

Цитата: Kogrom
Оценил сколько параметров взаимодействуют в одном методе.


А что плохого в том, что в одном месте мы спрашиваем, а в другое отсылаем? Там по одному методу везде вызывается.

Цитата: Kogrom

 
Код:
using (var stream = new FileStream(fileName, FileMode.Create))
using (var xmlWriter = new XmlTextWriter(stream, Encoding.UTF8))

Или FileStream и XmlTextWriter не являются библиотечными классами?

Являются. А что плохого в том, что я складываю XML в файл? Если бы я использовал юнит тестирование, то в тесте у меня было бы сравнение содержимого файлов. ;)

Цитата: Kogrom
Почему это не тот случай? Почему нельзя компьютеру поручить посмотреть чего и как она считает?

Потому что подсчет зависит не от этой программы, а от базы, в которую она шлет запросы.

Цитата: Zorkus
Вротмненоги! Модификаторы доступа на уровне методов -> плохая архитектура?!


Во-во. :D

5
04 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Zorkus
Вротмненоги! Модификаторы доступа на уровне методов -> плохая архитектура?!


Надо видимо договориться о том, что такое архитектура...

6
04 февраля 2011 года
George
4.1K / / 05.01.2007
Цитата: Kogrom
Докажи обратное - буду только рад. Пример приведи какой-нибудь :)


Тут нужно понимать, что инкапсулирование - это общепринятый и давноиспользуемый подход. Так что доказывать, что "она вертится" придется именно тебе. :) Пока что ты, судя по всему, этого не сделал.

241
04 февраля 2011 года
Sanila_san
1.6K / / 07.06.2005
Цитата: Kogrom
Докажи обратное - буду только рад. Пример приведи какой-нибудь :)

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

63
05 февраля 2011 года
Zorkus
2.6K / / 04.11.2006
Для оценки сложности методов есть общепризнанная методика - цикломатическая сложность кода. Ее среднее значение для всех методов модуля, хотя и является "средней по больнице", все же описывает - код "скорее нагроможденный и сложный для чтения и понимания" или нет.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог