Страницы

Поиск по вопросам

Показаны сообщения с ярлыком ооп. Показать все сообщения
Показаны сообщения с ярлыком ооп. Показать все сообщения

среда, 15 апреля 2020 г.

Как правильно сохранить данные в бд

#python #ооп #django

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


Ответы

Ответ 1



Если вопрос концептуальный, то есть понятно как написать код, но непонятно куда его положить, то я бы посоветовал не прикручивать к парсеру функционал сохранения данных. Можно это сохранение сделать во вьюхе, а совсем хорошо написать отдельный модуль с классом-контроллером, который бы получал данные для сохранения, дальше итерировался по ним и создавал/сохранял модели, сформированные из этих данных (ну там MyModel.objects.create(arg1=arg1, arg2=arg2) и т.д.) В этом случае во вьюхе можно получить данные из парсера и передать их экземпляру контроллера, который их и сохранит. Вся логика по обработке данных будет располагаться в объекте контроллера, что удобно и красиво будет. upd Заведите модуль в директории с приложением, назовем его controllers.py # controllers.py class LessonController(object): def __init__(self, data): super(LessonController, self).__init__() self.data = data def save_parsed_data(self): for item in self.data: Lesson.objects.create( subject=item.subject, teacher=item.teacher, ... ) # views.py from controllers import LessonController def my_view(request): x = Parser("D:/rsp.xls") schedule = x.parse() lesson_ctl = LessonController(schedule) lesson_ctl.save_parsed_data Ну вот что-то в этом духе может вам подойдет.

Ответ 2



Привет. Смутно понятно как-то, но если это то, что я понял, сделайте во вьюшке так, например: from .models import Имятвоеймодели def some_function(request): че-нибудь = Имятвоеймодели() че-нибудь.полемодели = какие-тоданныеотпарсера че-нибудь.save() А вообще подробнее опишите свой парсер, дайте пример кода.

Ответ 3



А почему бы не импортировать sql драйвер и уже от этого плясать, данные записать в переменные и их передать в базу? import sqlite3 например.

четверг, 9 апреля 2020 г.

Насколько важно не потерять инкапсуляцию на уровне пакета?

#java #ооп

                    
Я пишу проект на java. Создавал все классы в одном пакете и в один момент их количество
достигло 20. И это только те, которые отвечают за GUI. тогда я решил что надо разбить
их по пакетам :) Многие из этих классов - это мои наследники классов Swing - MyScroll,
MyButton и т.д. Всего около 10 таких классов. Их используют другие 10 классы, занимающиеся
непосредственно построением GUI. Сейчас эти 10, которые являются наследниками классов
Swing у меня не являются публичными. А если я их вынесу в отдельный пакет их придется
сделать публичными. Очень интересно стоит ли их выносить и какие вообще могут быть
рекомендации по этой теме? Ведь с одной стороны, проект будет лучше структурирован,
с другой стороны я  потеряю инкапсуляцию на уровне пакета, правильно? Гуглил - не нашел.
В книгах тоже - просто сухой текст насчет того что такое пакеты, как их создавать и
как импортировать. А хотелось бы поглубже разобраться.
    


Ответы

Ответ 1



20 классов в пакете — это в целом не очень много. К примеру, в Java-8 в пакете java.util 116 файлов .java (не считая подпакетов). Поэтому пока повода для беспокойства нет. Не забывайте про другой способ организации исходников: можно использовать вложенные классы. Если, например, в вашем пакете com.example есть классы, рисующие интерфейс MyButton, MyLabel и есть некий главный класс типа MyWindow или MyFrame, часто разумно вспомогательные классы разместить внутри: public class MyFrame extends JFrame { private static class MyButton extends JButton { ... } private static class MyLabel extends JLabel { ... } ... } Такой код проще читать: понятно, что MyButton и MyLabel используются только MyFrame. Конечно, тут тоже надо знать меру: если вложенных классов много, размер исходника вырастет до некомфортных размеров. Альтернативный подход — использовать модульную систему типа OSGi, где каждый jar — это отдельный модуль или плагин, который может определить (в файле MANIFEST.MF) экспортируемые и неэкспортируемые пакеты. Тогда вы можете иметь com.example, содержащий публичные классы, и, например, com.example.internal, содержащий детали реализации. Классы из internal будут тоже объявлены публичными, но плагин не будет экспортировать этот пакет, поэтому из других плагинов в OSGi-приложении он не будет доступен. Что-то подобное нам предложит Java-9 и проект Jigsaw: там можно будет создать файлик module-info.java и написать, какие пакеты видны за пределами данного модуля.

Ответ 2



Честно говоря, не очень понятна структура проекта и по этому сложно прямо вот так дать какую-то рекомендацию. Логично предположить, что кто-то из классов, которые отвечают за построение GUI, должен быть виден наружу, просто для того, чтобы запустить отрисовку. Можно например вынести их в отдельный пакет и сделать package private, а затем, например, создать там же какой-нибудь public class GUIBuilder с методом build(), который будет запускать всю процедуру. Лично я выношу классы в отдельный пакет для группировки функционала

четверг, 2 апреля 2020 г.

Создание объекта класса через родителя. Python

#python #ооп

                    
Пишу калькулятор на python. У меня есть 2 типа кнопок: цифры и  операции. Описал
3 класса: класс кнопки(родитель), классы кнопки-операции и кнопки-цифры(дочерние).

class Button:
    pass

class NumberButton(Button):
    pass

class OperationButton(Button):
   pass


Есть макет калькулятора, сделанный на PyQt5, где каждая кнопка имеет имя:

а) num0, num1, num2, ... , num9 - кнопки цифр

б) op_plus, op_minus,  op_divide, op_multiply - кнопки операций

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

Хочу:

button = Button(button_name)


Не хочу:

if button_name == num0 or ... button_name == num0:
    button = NumberButton(button_name)
else:
    button = OperationButton(button_name)

    


Ответы

Ответ 1



Примерно как-то так: class Button: def __new__(cls, name): if 'num' in name: return NumberButton(name) else: return OperationButton(name)

понедельник, 30 марта 2020 г.

Как правильно понимать приватные свойства в ООП?

#javascript #ооп


Куда сохраняются приватные свойства созданного объекта? Например у нас есть такой код:



function User() {
  var firstName, surname;

  this.setFirstName = function(firstNameUser) {
    firstName = firstNameUser;
  }

  this.setSurname = function(surnameUser) {
    surname = surnameUser;
  }

  this.getFullName = function() {
    return surname + ' ' + firstName;
  }

}

var user1 = new User();
user1.setFirstName('Phillip');
user1.setSurname('Moore');

console.log(user1)
console.log(window.surname)




Мы создаем приватные свойства firstName и surname, но после создания нового объекта
через конструктор, этих свойств нет в этом объекте. И в глобальной области видимости
этих свойств тоже нет, куда они тогда сохраняются? 
    


Ответы

Ответ 1



Они хранятся в замыкании. Вот более просто пример этого механизма function setSecret(secret) { const mySecret = `My secret: ${secret}`; return function getSecret() { return mySecret; } } const secret1 = setSecret('secret 1'); const secret2 = setSecret('secret 2'); secret1(); // secret 1 secret2(); // secret 2 В данном случае, при каждом вызове функции setSecret, создается локальная область видимости ( об А ), где хранится одна переменная mySecret. В обычном случае после выполнения функции, об А бы уничтожилась и переменная пропала, НО мы возвращаем функцию, которая имеет доступ к созданной об А, поэтому об А сохраняется. В вашем случае механизм тот же: функция возвращает объект, у которого есть методы, использующие область видимости этой функции.

sealed, virtual, невиртуальные методы в C# и производительность

#c_sharp #net #ооп #производительность #clr


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

class X
{
    public int NonVirtual() => DateTime.Now.Millisecond;
    public virtual int Virtual() => DateTime.Now.Minute;
}

class Y : X
{
    public override int Virtual() => DateTime.Now.Millisecond;
}

class Program
{

    private static volatile int TST = 0;

    static int Slow(Y x) => x.Virtual();

    static int Fast(Y y) => y.NonVirtual();

    static void Main(string[] args)
    {

        int i = 0;
        var stopwatch1 = new Stopwatch();
        var stopwatch2 = new Stopwatch();

        stopwatch1.Start();
        var y = new Y();
        for (i = 0; i < 100000000; i++)
        {
            TST = Fast(y);
        }
        stopwatch1.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch1.Elapsed);

        stopwatch2.Start();
        for (i = 0; i < 100000000; i++)
        {
            TST = Slow(y);
        }
        stopwatch2.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch2.Elapsed);

        Console.ReadKey();
    }
}


Поле TST объявлено как volatile, чтобы компилятор не оптимизировал вызовы.

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

Тогда я полез в IL:

IL_0001: callvirt  instance int32 PerformanceTests.X::Virtual()


Это вызов виртуального метода. Вроде всё нормально. Второй вызов:

IL_0001: callvirt  instance int32 PerformanceTests.X::NonVirtual()


Что, простите? callvirt? Разве тут не должно быть call? sealed так-же никак не влияет
на вызов виртуального метода.

Хотел бы выяснить у более опытных коллег, всё-таки, есть ли смысл в запечатывании
классов в плане производительности? А так-же, почему вызов невиртуальной функции в
IL такой же как и виртуальной?

Update:
В комментариях @Grundy написал, что callvirt - из-за того, что метод объявлен в базовом
классе. Переписал код так, что теперь используется базовый класс (т.е. Y - не используется).
callvirt так и вызывается.
    


Ответы

Ответ 1



Как уже сказали в комментариях, компилятор использует callvirt что бы генерировать NullReferenceException. Что бы получить чистую call инструкцию компилятор должен быть уверен, что экземпляр класса не может быть null. Пример: class Test { public void Method() => Console.WriteLine(123); } static void Main(string[] args) { new Test().Method(); } IL-код: IL_0001: newobj instance void ConsoleApp1.Program/Test::.ctor() IL_0006: call instance void ConsoleApp1.Program/Test::Method() Если код немного изменить: static Test GetTest() => new Test(); static void Main(string[] args) { GetTest().Method(); } То уже получаем callvirt, так как компилятор предполает, что GetTest может вернуть null: IL_0001: call class ConsoleApp1.Program/Test ConsoleApp1.Program::GetTest() IL_0006: callvirt instance void ConsoleApp1.Program/Test::Method() sealed ни на что не влияет в рантайме. Это просто маркер для разработчиков, который сообщает, что можно делать в высокоуровневом коде, а что нельзя. Для каждого callvirt невиртуального метода JIT вставляет одну дополнительную инструкцию перед каждым call: cmp dword ptr [/*здесь регистр с адресом экземляра*/],ecx call 00007FF9CD540098 // метод Эффект от одной cmp инструкции очень незначителен.

вторник, 17 марта 2020 г.

ООП ради ООП

#ооп #классы


Доброго времени суток!
Есть, к примеру, класс Cat, который реализует интерфейс Movable, инкапсулирует цвет
и прочее.    Имеет ли смысл создавать подклассы BlackCat, WhiteCat и т.д., которые,
по сути дела, ничего нового не привносят? Правильно ли в таком случае создавать enum
Сats и уже конкретный экземпляр enum'а (со своими полями) передавать в конструктор
класса Cat, а там присваивать значения полей?    


Ответы

Ответ 1



Переменные аспекты (условия/реализации или как удобней их называть) лучше всего всегда отделять от тех, которые являются постоянными. Это правило как один из принципов проектирования. Если следовать ему, то тут уж надо выделять отдельный интерфейс с реализациями цвета или, как предложили, создать перечисление. Например, если цвет будет переливающимся и становиться другим в зависимости от условий (допустим, от освещенности комнаты, где находится кошка), то уже перечислением не обойтись, а надо делать интерфейс и реализовывать отдельное поведение для отдельных цветов кошки. В итоге у нас может получиться один абстрактный класс или интерфейс Cat с реализацией, например, BadCat и GoodCat. Также будет интерфейс Colorable и конкретные реализации, например, WhiteColor, BlackColor.

Ответ 2



Говорить о сферических котах Шредингера в вакууме довольно сложно, поскольку не факт, что удастся перенести полученный в этом вопросе опыт в реальное приложение. Есть ряд простых, которые могут сказать, стоит или нет использовать наследование, или некоторый аспект должен быть лишь свойством. Отношение "Является" против отношения "является свойством". Итак, можно ли сказать, что черный кот является котом в том же смысле, что и "кот является млекопитающим"? Т.е. является ли цвет некоторой характеристиков поведения моделируемой сущности, которая является неизменной во времени? Можно ли сказать, что "черные коты" образуют определенную группу животных (котов), принадлежность к которым существенно меняет их собственное поведение? Или же можно сказать, что цвет - это один из атрибутов конкретного экземпляра, который, к тому же, может поменяться со временем? Поскольку второе высказывание кажется более логичным, то и предпочтение стоит отдать свойству Color, а не подклассам BlackCat, RedCat и т.д. У этого подхода есть ряд очень важных следствий. Когда что-то моделируется с помощью класса, то созданный объект намертво к нему привязывается. У созданного объекта кот нельзя поменять цвет, что вполне может быть реальным при моделировании некоторого поведения (например, кот постарел, его обрили). К тому же, иерархии плохо расширяются. Это значит, что для добавления нового цвета придется изменять иерархию, что существенно сложнее добавления нового перечисления или путем просто использования другого значения из стандартного перечисления Color. Наследование предназначено для моделирования некоторого подмножества в общем семействе объектов. Также, наследование является очень жесткой связью, которую невозможно изменить после создания объекта, а также сложно расширять. Большинство современных языков не обладают множественным наследованием реализации, что не позволит в случае наследования цветастости котов, добавить другую "проекцию" наследования, например, по породе котов или другому признаку.

воскресенье, 15 марта 2020 г.

как правильно устранить “запах” кода “Большой класс”?

#ооп #рефакторинг


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

private static JPanel createTasksMainInfoPanel(JTabbedPane taskTabbedPane) {
    JPanel panelForMainInfo = new JPanel();
    //code...
    addComponentForMainInfoBox(verticalBoxForTaskMainInfo, new String(),
            createTypeChoicePanel(max, min));
    JButton ok = new JButton("OK");
    createListenerForOk(ok, fieldForName, fieldForVarQuantity,
            FieldForLimitQuantity, FieldForCritQuantity, max,
            taskTabbedPane);
    addComponentForMainInfoBox(verticalBoxForTaskMainInfo, new String(), ok);
    panelForMainInfo.add(verticalBoxForTaskMainInfo);
    return panelForMainInfo;
}


Здесь я привел только начало и конец метода. В середине еще строк 50. Плюс в конце
у меня идут вызовы других методов, которые так же нужны что бы создать эту панель.
В них приходится передавать кучу параметров. В общем, в результате я имею длинные методы
с большим списком параметров. И мой класс, где создается GUI разрастается до огромных
размеров. Не лучше ли мне выделить для создания этой панели отдельный класс? Тогда
все что я передавал в параметрах можно было бы сделать полями этого класса. И можно
было бы выделить более компактные методы и без огромных списков параметров. Или может
я вообще зря это затеял. Ведь добавится еще один класс, а значит новые связи между
классами. К тому же, не противоречит ли это принципу единственной обязанности(single
responsibility principle)? Ведь эта панель входит в GUI, то есть ее отрисовка входит
в обязанность этого класса GUI?
    


Ответы

Ответ 1



Под "большим классом" Фаулер понимает не размер в строках, а размер функциональности. То есть когда в классе много разнородных ответсвенностей класс считается "большим". Следовательно чтобы назвать класс "большим" надо составить перечень его ответсвенностей и определить насколько они разнородные. В вашем случае функция класса состоит в сопоставлении визуальной структуры гуя и внутренней структуры гуя. Поэтому на нем лежит две ответсвенности: знать визуальную структуру и знать внутреннюю структуру. Визуальная структура гуя это то, что мы видим на экране: кнопка внутри панельки, панелька на форме, форма слева на окне, нажатие на кнопку выводит диалог, и так далее. Тут все понятно. Внутренняя структура гуя это то, как связаны объекты контролов между собой: кто кого содрежит, кто кому сообщения посылает, как контролы создаются и настриваются, и прочее. Но к внутренней структуре гуя (именно гуя) не относится то как объекты контролов связаны с другими объектами неконтролами! Это другая ответсвенность. Судя по коду, который вы привели, у вас ничего такого не наблюдается, поэтому ваш класс нельзя назвать "большим". Если вас смущает его размер посмотрите на это с другой стороны. Сейчас у вас одно место где весь гуй создается и настривается, то есть когда вы хотите что-то поменять на форме вам не надо вспоминать в какой файл смотреть - это один и тот же файл. Если вы разнесете эту логику по 10 классам, то у вас будет 10 мест для поиска.

пятница, 13 марта 2020 г.

Вывод метода объекта имя которого заданное в переменной [дубликат]

#javascript #json #ооп #объекты


        
             
                
                    
                        
                            На этот вопрос уже дан ответ здесь:
                            
                        
                    
                
                        
                            Как вставить(экранировать) переменную в место перед точкой JS
                                
                                    (1 ответ)
                                
                        
                                Закрыт 4 года назад.
            
                    
Как вывести с объекта foo тот метод, который задан в переменной obl?

var foo = {
   pr: "aaa",
   wr: "bbb",
   bg: "ccc"
};

var obl = 'pr';

document.write(foo.obl);

    


Ответы

Ответ 1



Это называется Bracket Notation(Скобочная нотация) document.write(foo[obl]);

Как избавиться от параллельных иерархий наследования?

#java #ооп #архитектура


Я решаю задачу о нахождении лидера (leader election)
Это чисто алгоритмическая задача, у которой есть 2 формы: однонаправленное кольцо
и двунаправленное. Для представления данных я создал свой собственный класс для списка,
закрученного в кольцо. То есть у меня два алгоритма, по одному для каждой формы задачи.

public abstract class MyAbstractRoundList {

    protected int size;
    protected Agent[] arr = new Agent[1];
    protected int index = 0;

    public boolean isEmpty() {
        return size == 0;
    }

    public int size() {
        return size;
    }

    public void add(Agent agent) {
        if (size >= arr.length) {
            Agent[] temp = arr;
            arr = new Agent[temp.length * 2];
            System.arraycopy(temp, 0, arr, 0, temp.length);
        }
        arr[size++] = agent;
    }
// и дальше еще много методов


Далее я создаю наследников этого класса для однонаправленного режима и для двунаправленного.
Реализации в них конечно различаются. Далее, у меня есть класс:

public class LeaderElection {

public static void solve(MyAbstractList list, int i) {
    if (i == 0) {
        list.initiateStartState();
    } else {
        list.setMessages();
    }
}


}

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

    if(isOneDirectMode()){
        LeaderElection.solve();
    {
    if(isBiDirectMode()){
        BiLeaderElection.solve();
    }


Я мог бы так же создать абстрактный класс для решения и его наследников и пользоваться
полиморфизмом (так я и делаю для списков). Но вот тут и возникает проблема: у меня
получаются параллельные иерархии наследования. Если появится новый режим я должен буду
добавить новый класс подкласс MyAbstractRoundList и новый подкласс решения. Можно как
то избавиться от этого? Я вижу только один способ: Можно было бы сделать в MyAbstractRoundList
абстрактный метод solve() и реализовывать его в подклассах каждого режима так как это
требуется для конкретного режима. Но это плохо, потому что тогда у меня подклассы MyAbstractRoundList
будут не только хранить данные, но и решать задачу. То есть выполнять 2 функции.
    


Ответы

Ответ 1



Они не параллельны. Изменения в одной иерархии никак не влекут за собой изменения в другой иерархии. Если появится новый режим я должен буду добавить новый класс подкласс MyAbstractRoundList и новый подкласс решения. Можно как то избавиться от этого? Я вижу только один способ: Можно было бы сделать в MyAbstractRoundList абстрактный метод solve() и реализовывать его в подклассах каждого режима так как это требуется для конкретного режима. Решение задачи - это поведение. Поведение лучше описывать интерфейсами. public interface Solver { void solve(MyAbstractList list, int i); } ... public class LeaderElection implements Solver { ... public class BiLeaderElection implements Solver { ... public class MultiTreadingLeaderElection implements Solver { У вас отдельная иерархия наследования классов, отвечающих за хранение данных, и отдельная иерархия классов, отвечающих за решения. Это нормально. Если появится новый вид хранения (новый тип списка), вы добавите новый класс-наследник MyAbstractRoundList. Это никак не связано с решениями, новый класс может использоваться и существующими решениями. Если потребуется добавить новый способ решения, вы добавите новый класс, реализующий интерфейс Solver, и это не обязательно должно отразиться на иерархии классов для хранения. При таком подходе у вас всегда будет работать код solver.solve(abstractList, i);, если в переменную solver положить объект любого класса, реализующего интерфейс Solver, а в переменную abstractList - любой объект класса-наследника MyAbstractRoundList, и самое главное - этот код не придется менять при добавлении новых классов, как и должно быть с точки зрения ООП. UPD. Есть данные, есть поведение. В рамках класса поля описывают данные, методы - поведение. Например, я руковожу бригадой роботов. Одни из них могут строить, другие - переносить, третьи - разрушать, четвертые - поливать. Робот-строитель, например, может принести себе стройматериал, но только в небольшом количестве, таким образом, он может и строить, и носить. А робот-носитель - только носить. И если вдруг поступает задача срочно разгрузить вагон стройматериалов, то мне надо собрать всех роботов, умеющих носить. И мне плевать, что это за роботы. Хоть робот-поливалка. Если может носить - пусть идет носить. Я просто выберу роботов с нужным мне поведением, и буду уверен, что они смогут сделать то, что мне надо. public interface Carrier { void carry(); //нести } public interface Builder { void build(); //построить } public interface Destroer { void destroy(); //сломать } public class RobotBuilder extends Robot implements Builder, Carrier { public void carry() { } public void build() { } } public class RobotDestroer extends Robot implements Destroer { public void destroy() { } } public class RobotCarrier extends Robot implements Carrier { public void carry() { } }

воскресенье, 8 марта 2020 г.

Экспорт модели в .xlsx соблюдая SOLID

#c_sharp #ооп #шаблоны_проектирования #solid


В БД есть таблица результатов тестирования по русскому языку и математике (SubjectCode=2):

dbo.Result


Во второй таблице находятся просто сведения о школах:

dbo.School



Таких результатов бывает 40.000-70.000. Нужно на выходе получить для каждого тестируемого
вот такой отчет в pdf-файле:



Мое решение:


Создал Excel-шаблон;
Беру данные из базы и заношу их в этот xlsx-шаблон;
Сохраняю этот шаблон в pdf-файл;
И так для каждого ученика.




LearnerReport.cs

namespace so16092016.Models
{
    public class LearnerReport
    {
        public string SNS { get; set; } //Surname Name SecondName
        public string SchoolName { get; set; }
        public string ClassName { get; set; }
        public int TestResult5 { get; set; }
    }
}


Program.cs

using Excel = Microsoft.Office.Interop.Excel;

namespace so16092016
{
    class Program
    {
        static void Main(string[] args)
        {
            resultsEntities context = new resultsEntities();
            ResultsRepository resultsRepository = new ResultsRepository(context);
            var ma_results = resultsRepository.GetTList().Where(x => x.SubjectCode
== 2); //получить результаты по математике

            Excel.Application app = new Excel.Application();
            app.DisplayAlerts = false;
            Excel.Workbook book_template = app.Workbooks.Open(@"шаблон_отчета.xlsx");
            Excel._Worksheet sheet_template = book_template.Sheets["отчет"];

            foreach(var ob in ma_results)
            {
                //1. Создаем объкт LearnerReport из БД
                LearnerReport report = new LearnerReport
                {
                    SNS = $"{ob.surname} {ob.name} {ob.SecondName}",
                    SchoolName = ob.SchoolName,
                    ClassName = ob.ClassName,
                    TestResult5 = ob.TestResult5                     
                };

                //2. Экспорт объкта LearnerReport в шаблон xlsx
                sheet_template.Range["C4"].Value2 = report.SNS;
                sheet_template.Range["C5"].Value2 = report.SchoolName;
                sheet_template.Range["C6"].Value2 = report.ClassName;
                sheet_template.Range["C9"].Value2 = report.TestResult5;

                //3. Сохраняем полученный файл в .pdf на рабочем столе
                string file_name = $@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\{report.SNS}.pdf";
                sheet_template.ExportAsFixedFormat(Excel.XlFixedFormatType.xlTypePDF,
file_name);
            }

            book_template.Close(0);
            book_template = null;
            app.Quit();
            app = null;
        }
    }
}


Необходимо: Приложение работает и дает необходимый результат. Но вы наверное видите,
что оно далеко от ООП (SOLID) и как результат очень трудно его "допиливать" и масштабировать.
Помогите правильно спроектировать данный механизм формирования подобных отчетов: 


логика экспорта модели в .xlsx должна быть у самой модели или
необходимо создать отдельный класс-менеджер для этого?
какие должны быть модели?
как правильно создавать модель-отчета на основе объектов БД? 
какой порождающий паттерн здесь больше подходит?

    


Ответы

Ответ 1



Конкретно в вашем случай нет необходимость, применять какие либо паттерны, т.к. у вас довольно простая программа и паттерны добавят лишь ненужную сложность (применять паттерны ради паттернов плохая практика). Паттерны сгодятся если вы пишите большие Enterprise приложения, где необходима гибкость и масштабируемость. Если я правильно понял, то вы хотите отрефакторить программу. 1) Из кода я не понял что вы используете для получения данных из БД, но посоветовал бы использовать какую нибудь ORM, например Entity Framework 6. Создать DbContext и использовать его в репозиториях ResultsRepository и SchoolRepository Все выборки засунуть в соответствующий репозиторий например class ResultsRepository { // возвращает все результаты public IEnumerable GetResults() // возвращает все результаты по заданому предмету. public IEnumerable GetResults(Subject subject) // возвращает все результаты для заданой школы. public IEnumerable GetResults(int idSchool) // возвращает все результаты для заданой школы по заданому предмету. public IEnumerable GetResults(int idSchool, Subject subject) } class SchoolRepository { // возвращает список всех школ. public IEnumerable GetSchools() } 2) Модель данных приблизительно выглядит так class Result { [Key] public Guid Id { get; set; } public string Surname { get; set; } public string Name { get; set; } public string SecondName { get; set; } [NotMapped] public string SNS => $"{Surname} {Name} {SecondName}"; public School School { get; set; } public string ClassName { get; set; } public Subject Subject { get; set; } public int TestResult5 { get; set; } } class School { [Key] public int Id { get; set; } public string Name { get; set; } } enum Subject { RussianLanguage = 1, Mathematics = 2 } 3) Можно создать отдельный класс для работы отчётами class LearnerReportManager { public Excel._Worksheet CreateReport(Result result) public SaveReport(Excel._Worksheet reportWorksheet, string fileName) } 4) Для формирования Excel отчёта луче используйте EPPlus или более крутой File Formats от Syncfusion (у них есть бесплатная версия). вы так не будите зависеть от установленного MS Office. 5) Если кол. формируемых отчетов за раз от 40 до 70 тыс., то было бы не плохо добавить многопоточное создание отчетов, это существенно уменьшит время создания отчётов.

Связи в Объектно Орентированном Программировании c#

#c_sharp #ооп


Всем привет:)
Друзья, подскажите пожалуйста, если Я передаю ссылку на объект в метод, какая это связь? 

public void Method(MyClass my) // какая связь?
{
    //..
}


Если можно скиньте ссылки!   

Композиция - всё ясно.

public class ElectricEngine { }

public class Car
{
    ElectricEngine engine;
    public Car()
    {
        engine = new ElectricEngine();
    }
}


Агрегация

public abstract class Engine
{ }

public class Car
{
    Engine engine;
    public Car(Engine eng)
    {
        engine = eng;
    }
}


Ассоциация

class Team
{

}
class Player
{
    public Team Team { get; set; }
}


Наследование и реализация - тоже не вызывают проблем)
    


Ответы

Ответ 1



Это зависимость. Вообще, я не встречал четкого определения для связи "Зависимость", но во многх источниках под ней подразумевают два случая. Параметер в методе public void Method(MyClass my) { // ... } Создание локальной переменной public void Method() { MyClass my = new MyClass(); // ... } Если брать UML, то в нем определены еще конкретные зависимости: call, create, use и т.п.

Вызвать конструктор наследника в абстрактном классе

#java #ооп


Как вызвать в абстрактном классе конструктор того класса, конкретно который его наследует?
Типа такого:

public abstract class AbstractClass {

    public Abstract foo() {
        //Когда метод foo вызовется наследником
        AbstractClass a = new this(); //здесь надо вызвать конструктор наследника
        a.bar(); //как-то меняем состояние, вызывая метод наследника
        return a; //и возвращаем экземпляр наследника
    }

    public abstract void bar();
}


Но в данном примере выдает ошибку:


  java: as of release 8, 'this' is allowed as the parameter name for the
  receiver type only, which has to be the first parameter

    


Ответы

Ответ 1



Прежде всего в хорошем дизайне базовый класс ничего не должен знать о своих наследниках, иначе нарушается одна из основ ООП о программировании по контракту. Сделайте еще один абстрактный метод и переопределяйте его в наследниках таким образом, чтобы они возвращали новые экземпляры своего типа: public abstract class AbstractClass { public AbstractClass foo() { AbstractClass a = createInstance(); a.bar(); return a; } public abstract void bar(); protected abstract AbstractClass createInstance(); } public class ConcreteClass extends AbstractClass { protected override AbstractClass createInstance() { return ConcreteClass(); } } Если все-таки не хочется трогать наследников и пойти грязным путем, то можно использовать рефлексию (однако в таком случае у всех наследников должен быть конструктор без параметров): public Abstract foo() { AbstractClass a = this.getClass().newInstance(); a.bar(); return a; }

Нужно ли разделять интерфейсы и абстрактные классы в С++

#cpp #ооп #интерфейс


Как известно, отдельных языковых средств для объявления интерфейсов в С++, а их роль
могут выполнять абстрактные классы.
Но с идеологической точки зрения интерфейсы и абстрактные классы являются довольно
разными сущностями. Интерфейсы описывают некий контракт того, как можно взаимодействовать
с классом. Абстрактные классы являются корнем иерархии классов, используются для полиморфизма
в духе 

AbstractSuperClass* a = new SubClass;


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

Нужно ли, программируя на С++, разделять эти понятия и писать интерфейсы, как в Java/C#?
Или можно(нужно?) смешивать и использовать только абстрактные классы?  
    


Ответы

Ответ 1



В C#/Java нет множественного наследования классов, но есть множественное наследование интерфейсов. Поэтому в этих языках разделять интерфейсы и абстрактные классы приходится волей-неволей. В С++ такого ограничения нет, поэтому нет особой надобности в выделении отдельного понятия "интерфейс", и отделения его от абстрактного класса. Интерфейсом может служить любой абстрактный класс, ему даже не обязательно иметь публичных виртуальных функций (ну, кроме деструктора, если нужно полиморфное удаление). Пример такого интерфейса - паттерн NVI. При желании более соответствовать ООП парадигме языков C#/Java можно давать интерфейсным классам имена, начинающиеся с буквы I, или даже добавить #define interface struct чтобы выделить интерфейсный класс при объявлении/определении. Такие подходы используются в MS COM. Но в общем случае, этого не требуется, а проблему ромбовидной иерархии можно решить через виртуальное наследование.

Структура классов в проекте java

#java #ооп #проектирование


В Desktop Swing приложении есть класс Item в пакете Data, класс ItemFrame (графическое
заполнение и редактирование класса Item) в пакете GUI и класс NetWorker в пакете NetDB
для работы с DB и сетью. Имена классов и пакетов - условные.

По логике программы, при создании (и редактировании) экземпляра класса Item вызывается
графический интерфейс ItemFrame в который заносятся данные, при нажатии кнопки "Сохранить"
создается объект Item, который должен быть записан в DB и, при определенных условиях,
должны вызываться методы для его передачи по сети и записи в XML.

Получается, что при нажатии кнопки вызывается конструктор Item из другого пакета,
и методы по работе с DB и сетью из третьего. Выглядит немного запутанно.
Как в таком случае правильно организовать структуру, в каком классе какие методы
лучше реализовать?

Интересует именно правильное решение с точки зрения ООП.
    


Ответы

Ответ 1



Вы на верном пути. Разделение пакетов по обязанностям -- это правильно. Тот факт, что при этом будет какое-то место, которые вызывает код из нескольких пакетов -- неизбежен. Возможно вам стоит придерживаться классической трехслойной архитектуры UI->BLL->DAL (стрелками обозначено направление взаимодействия). Первый и последний слои у вас уже есть, осталось ввести слой бизнес-логики. UI будет передавать ему данные (или уже заполненный Item), BLL будет создавать/брать переданный Item и образаться к NetDB для сохранения.

суббота, 7 марта 2020 г.

Странное поведение ограничений в обобщенном методе

#c_sharp #net #ооп


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

public static class JSON
    {
        public static string Serialize_object_TO_JSON(this T Entity)
         where T:ENT
        {
            return JsonConvert.SerializeObject(Entity);
        }

    }


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

public static class JSON
        {
            public static string Serialize_object_TO_JSON(this T Entity)
             where T:List
            {
                return JsonConvert.SerializeObject(Entity);
            }

        }


После чего компилятор говорит, что ему не удалось привести тип класса, который наследуется
от ENT, к типу List. 

P.S. Изначально задавать обобщение конечного класса я не могу, т.к. их довольно много,
именно по этому попытался делать через наследование.
    


Ответы

Ответ 1



Попробуйте так, если Вам это разрешает бизнес логика: public static class JSON { public static string Serialize_object_TO_JSON(this T Entity) where T : IEnumerable { return JsonConvert.SerializeObject(Entity); } } Дело в том что List - инвариантен. И все классы в .NET инвариантны. То есть это полное соответствие типов. Означает, что можно использовать только изначально заданный тип. Таким образом, параметр инвариантного универсального типа не является ни ковариантным, ни контравариантным. С другой стороны есть IEnumerable где тип-параметр T помечен как out - ковариантным. Позволяет использовать тип с большей глубиной наследования, чем задано изначально. Полное описание почему так +1 за хороший пример

Выделение памяти под константное свойство в классе

#c_sharp #ооп


Имеется класс:

public class SomeClass
{
    public SomeClass() { }

    public const int SomeUsefulValue = 42;
}


Создавая несколько (2 и более) экземпляров этого класса, память под константную переменную
выделится один раз и переменная будет одна для каждого экземпляра? Или же для каждого
экземпляра будет уникальная константная переменная?
    


Ответы

Ответ 1



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

четверг, 5 марта 2020 г.

перехват исключения производным классом

#cpp #ооп #классы #исключения


Объясните почему при вводе 0  и выбросе исключения Base, оно не отлавливается блоком
Derived1?

int main()
{
    int number = 0;

    for (;;)
    {
        try
        {
            cin >> number;
            cout << number << " ";

            switch (number)
            {
                case 0:
                    throw Base();

                case 1:
                    throw Derived1();

                case 2:
                    throw Derived2();
            }
        }
        catch (Derived1 /*exception*/)
        {
            cout << "Exception of derived class" << endl;
        }
        catch (Base /*exception*/)
        {
            cout << "Exception of Base class" << endl;
        }
    }

    return 0;
}

    


Ответы

Ответ 1



Потому что Base не является Derived, а вот Derived является Base. Вот если бы вы написали (кстати, перехватывайте исключения по ссылке, иначе столкнетесь со срезкой) catch (Base& /*exception*/) { cout << "Exception of Base class" << endl; } catch (Derived1& /*exception*/) { cout << "Exception of derived class" << endl; } то тут и Base, и Derived ловились бы первым блоком - Base.

Entity (сущности) — зачем они нужны?

#java #ооп #java_ee #entity


Всем добрый вечер.

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

Entity.java:

public class BaseEntity {
    protected Integer id;

    public BaseEntity() {
    }

    protected BaseEntity(Integer id) {
        this.id = id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getId() {
        return id;
    }

    public boolean isNew() {
        return (this.id == null);
    }

    @Override
    public String toString() {
        return String.format("Entity %s (%s)", getClass().getName(), getId());
    }
}


От него наследуется NamedEntity:

public class NamedEntity extends BaseEntity {

    protected String name;

    public NamedEntity() {
    }

    protected NamedEntity(Integer id, String name) {
        super(id);
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    @Override
    public String toString() {
        return String.format("Entity %s (%s, '%s')", getClass().getName(), id, name);
    }
}


А от него — User:

import java.util.Date;
import java.util.EnumSet;
import java.util.Set;

import static MealsUtil.DEFAULT_CALORIES_PER_DAY;

public class User extends NamedEntity {

    private String email;

    private String password;

    private boolean enabled = true;

    private Date registered = new Date();

    private Set roles;

    private int caloriesPerDay = DEFAULT_CALORIES_PER_DAY;

    public User() {
    }

    public User(Integer id, String name, String email, String password, Role role,
Role... roles) {
        this(id, name, email, password, DEFAULT_CALORIES_PER_DAY, true, EnumSet.of(role,
roles));
    }

    public User(Integer id, String name, String email, String password, int caloriesPerDay,
boolean enabled, Set roles) {
        super(id, name);
        this.email = email;
        this.password = password;
        this.caloriesPerDay = caloriesPerDay;
        this.enabled = enabled;
        this.roles = roles;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getRegistered() {
        return registered;
    }

    public void setRegistered(Date registered) {
        this.registered = registered;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public int getCaloriesPerDay() {
        return caloriesPerDay;
    }

    public void setCaloriesPerDay(int caloriesPerDay) {
        this.caloriesPerDay = caloriesPerDay;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public Set getRoles() {
        return roles;
    }

    public String getPassword() {
        return password;
    }

    @Override
    public String toString() {
        return "User (" +
                "id=" + id +
                ", email=" + email +
                ", name=" + name +
                ", enabled=" + enabled +
                ", roles=" + roles +
                ", caloriesPerDay=" + caloriesPerDay +
                ')';
    }
}


Я не совсем понимаю смысл такой "матрёшки". Внятного объяснения на русском не обнаружил.
Прошу поделиться смыслом сущностей, особенно меня интересует, почему мы пишем отдельно
id, отдельно name, отдельно всё остальное. Объяснение нужно прямо для чайников, а именно,
почему мы не можем без них обойтись или почему лучше их использовать. Также, подойдут
русскоязычные ресурсы, на которых разжёвывают, почему мы должны пользоваться сущностями
и вообще для чего они.
    


Ответы

Ответ 1



Решить каким образом использовать сущности и использовать ли их вообще поможет понимание следующей модели представления даннных. Когда мы говорим о сущностях в абстрактном смысле мы всегда в том или ином виде подразумеваем использование какой-либо модели данных. В частности, в программировании применяется EER-модель (Enhanced Entity-Relationship model). Расширенная модель включает все концепции ER-модели (entity-relationship model) и дополнительно включает понятия подкласса, суперкласса и относящиеся к ним понятия специализации, обобщения и категоризации. Далее рассмотрим базовую ER-модель. "Набор данных, обычно относящихся к какой-либо предметной области или тематической области, и структурированных таким образом, чтобы обеспечить установление отношений между отдельными элементами данных в соответствии с различными потребностями пользователей." G. Knott & N. Waites, Computing 3rd edition ER-модель, модель «сущность — связь» Модель была предложена в в 70-х годах Питером Пин-Шэн Ченом (сайт, статья). Модель "сущность-связь" основывается на некой важной семантической информации о реальном мире и предназначена для логического представления данных. Она определяет значения данных в контексте их взаимосвязи с другими данными. Важным для нас является тот факт, что из модели "сущность-связь" могут быть порождены все существующие модели данных (иерархическая, сетевая, реляционная, объектная), поэтому она является наиболее общей. Сущность фактически представляет из себя множество атрибутов, которые описывают свойства всех членов данного набора сущностей. Например, как у вас в коде. Есть базовая сущность BaseEntity, именованная сущность NamedEntity и конкретная User(пользователь). Таким образом сущность - это объект, который может быть идентифицирован неким способом, отличающим его от других объектов. Преимущества использования ER-модели Высокая гибкость. Обеспечивают: модульность, что позволяет переиспользовать код следуя принципу DRY; простоту рефакторинга Местная автономия. В каждой отдельной части программы можно работать только с нужными нам сущностями. Простота понимания. За счет семантического моделирования данных, при котором отдельная сущность опирается на смысл этих данных. Любую модель легко изобразить в виде диаграммы. Наличие и простота визуализации. Нотация П. Чена, Crow’s Foot, UML, DFD, IDEF0 и IDEF1x, нотация Мартина, нотация Бахмана и др. Недостатки использования ER-модели Сложность. Модель предназначена для высокого уровня абстракции. Увеличивается объем и сложность кодирования. Вам пришлось создать 3 класса со своими полями и методами, хотя можно было бы их оформить в одном классе. Кроме того разработчикам достаточно сложно хранить всю иерархию классов в голове. Безопасность. Трудно контролировать уровни доступности атрибутов сущности. Трудно поддерживать целостность. Такая модель чувствительна к изменению атрбутов.

среда, 4 марта 2020 г.

Клонирование объектов Java

#java #ооп #классы #объекты #клонирование


В классе main есть: 
 1) класс сlass1 в котором есть двумерный массив и еще несколько переменных 
 2) функция func(class1 cl) которая принимает объект класса но возвращает другой
тип данных (float), при этом внутри тела функции проводятся манипуляции с двумерным
массивом класса что бы получить ответ

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

Подскажите пожалуйста как решить эту проблему?
    


Ответы

Ответ 1



Сделайте class1 сериализуемым (добавьте implements Serializable в его определение). Сохраняем объекта класса в поток байтов: ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream ous = new ObjectOutputStream(baos); ous.writeObject(new class1()); ous.close(); теперь в func можно передать (class1)new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject() Таким образом объект класса сохраняется в поток из которого восстанавливаться независимый клон.

Ответ 2



Чтобы метод clone клонировал поля объекта, его нужно переопределить в самом классе. По умолчанию он оперирует только примитивными типами и указателями Но Вам нужно просто скопировать массив. Для этого есть метод Arrays.copyOf() или банально вызвать clone для массива Вот тут описаны разные методы получения копии массива https://stackoverflow.com/a/36513254/5376639

UpCast C#.Override и Virtual

#c_sharp #ооп #virtual #override


При создании класса  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Back
{
    class Bugay
    {
        public virtual void Method()
        {
            string b = "Base: ";
            Console.WriteLine(b  + "Здраствуйте,сударь");
        }
        public void Print()
        {
            Console.WriteLine("Class Bugay");
        }

    }
    class Bugay2 : Bugay
    {
        public override void Method()
        {
            string b = "NotBase: ";
            Console.WriteLine(b + "До свидания,сударь");
        }
        new public void Print()
        {
            //base.Print();
            Console.WriteLine("Class Bugay2");
        }

    }
    class OverVirt
    {
        static void Main(string[] args)
        {
            Bugay2 bugay = new Bugay2();
            bugay.Method();
            bugay.Print();
            Console.WriteLine(new string('-',20));
            Bugay nebugay = bugay;
            nebugay.Method();
            nebugay.Print();
            Console.WriteLine(new string('-', 20));
            Bugay nebugay2 = new Bugay();
            nebugay2.Method();
            nebugay2.Print();
            Console.WriteLine(new string('-',20));
            Bugay2 bugay2 = (Bugay2)nebugay;
            bugay2.Method();
            bugay.Print();
            Console.WriteLine(new string('-', 20));
            Console.ReadKey();
        }
    }
}


при UpCast  , метод который был пере-реализован с помощью override и virtual , вызывается
из класса который наследует базовый класс (Bugay2) , то есть который был пере-реализован
в этом классе Вывод:

NotBase: До свидания,сударь
Class Bugay2
--------------------
NotBase: До свидания,сударь
Class Bugay
--------------------
Base: Здраствуйте,сударь
Class Bugay
--------------------
NotBase: До свидания,сударь
Class Bugay2
--------------------


Почему вызывается метод не из базового класса? 
    


Ответы

Ответ 1



Смотрите. Разница между override-цепочкой и new-цепочкой методов состоит в следующем. При указании virtual/override вызывается метод у вашего реального типа, того, которым на самом деле обладает объект. То, какой при этом тип ссылки, по которой вы совершаете вызов, не важно, лишь бы тип этой ссылки содержал метод из вашей override-цепочки. Поэтому для метода Method() важно то, объект какого класса вы создаёте в реальности, а тип ссылки не важен. При указании new вызывается метод у вашего заказанного типа, то есть, типа ссылки, а не реального типа вашего объекта. Поэтому для метода Print() важно, какой тип вашей ссылки, а тип самого объекта не важен.