- Дублирование кода в конструкторах
Если несколько конструкторов должны выполнить идентичный код, то нет смысла дублировать его. В языке С++ можно вынести общий код в приватный метод, а затем в каждом конструкторе поместить вызов этого метода. В языке Java можно воспользоваться вызовом из одного конструктора другого:
public class Server {
private String address; public Server(String uri) { this.address = uri;
}
public Server(URI uri) { this(uri.toString());
}
}
Такой подход помогает решить еще одну проблему: модификацию внутренних (объектных) переменных в теле только одного конструктора.
Мы рассмотрели только несколько самых популярных ошибок начинающих при изучении программирования с использованием ООП. Одной из важнейших задач преподавателя курсов программирования будет осуществление контроля за появлением подобных ошибок и детальное разъяснение последствий их возникновения.
Литература
1. Штанюк А.А. Изучение объектных технологий в рамках курсов повышения квалификации // Международное научное издание Современные фундаментальные и прикладные исследования. 2014 №4 (15), с.20-23.
2. Штанюк А.А. Объектно-ориентированный подход и объектно-ориентированные языки как предмет изучения // Объектные системы. 2010. №2 (2). С. 68-70.
3. Common Pitfalls Developers Make with Object Oriented Programming [Электронный ресурс.] -Режим доступа: http://seguetech.com/common-pitfalls-developers-make-with-object-oriented-programming/ (дата обращения 29.12.2016).
4. S. Hubalovsky, J. Sedivy. Mistakes in object oriented programming // 2nd International Conference ob Information Technology (ICIT), 2010. 28-30 June 2010, Gdansk, Poland. pp 113-116.
5. Laplante, Phillip A.; Neill, Colin J. Antipatterns: Identification, Refactoring and Management. Auerbach Publications, 2005.
УДК 681.3
ПРИНЦИПЫ ПРОЕКТИРОВАНИЯ ANDROID-ПРИЛОЖЕНИЯ ДЛЯ АВТОМАТИЧЕСКОГО ОПРЕДЕЛЕНИЯ ОБЪЕМОВ ПАРТИИ БРЕВЕН
Малков Георгий Валерьевич, Уральский федеральный университет имени первого Президента России Б. Н. Ельцина, Нижнетагильский технологический институт (фил.), Факультет экономики и менеджмента, кафедра информационных технологий, студент, Россия, г. Нижний Тагил,
[email protected] Грегер Сергей Эдуардович, Уральский федеральный университет имени первого Президента России Б. Н. Ельцина, Нижнетагильский технологический институт (фил.), Факультет экономики и менеджмента, кафедра информационных технологий, доцент, Россия, г. Нижний Тагил,
segreger@gmail. com
Мухутдинов Руслан Маисович, Уральский федеральный университет имени первого Президента России Б. Н. Ельцина, Нижнетагильский технологический институт (фил.), Факультет экономики и менеджмента, кафедра информационных технологий, ассистент кафедры ИТ, Россия, г.Нижний Тагил,
На сегодняшний день смартфоны или планшеты чаще всего выступают в качестве устройства для потребления контента, однако гибкость платформы Android[1] и инструментарий Android SDK[2] позволяют разрабатывать приложения для любой области производственной деятельности [3], что обеспечит выполнение различных вычислений прямо на рабочем месте и существенно ускорит рабочие процессы организации или предприятия.
Разработка мобильных приложений с целью контроля качества и автоматизации процесса производства связана с использованием технологий машинного зрения, которые позволяют в автоматическом режиме распознать объекты на изображении выполнить необходимые расчеты с полученными объектами. Принцип работы любой системы машинного зрения можно разделить на несколько этапов:
1. Получение изображения наблюдаемого объекта;
2. Соотношение размеров изображения с размерами реальных объектов;
3. Автоматическое выделение наблюдаемого объекта, получение его параметров;
4. Сравнение полученных параметров объекта с эталоном, поиск дефектов и выполнение необходимых измерений;
5. Формирование отчета по полученным результатам.
В данной статье автор рассматривает особенности проектирования Android-приложения для автоматического определения объемов партии бревен прямо на промежуточных этапах приемки груза на всем транспортировочном пути. Данное приложение позволяет быстро и эффективно определить соответствие объемов принимаемых бревен с сопутствующими документами и при большом расхождении оперативно отреагировать на возникающую проблему, предотвратив экономические убытки организации. Также в случае соответствия объемов бревен приложение может автоматически сформировать отчетный документ с произведенными измерениями для дальнейшей обработки.
При разработке данного приложения первоначально стоит выделить основные рабочие экраны, на которых пользователь будет взаимодействовать с элементами управления:
1. Главное меню приложения, которое содержит элементы перехода на все остальные рабочие экраны;
2. Экран настроек, позволяющий пользователю задавать параметры для расчета объемов бревен, а также задавать поля для отчетного документа;
3. Хранилище обработанных отчетов для последующей отправки и корректировки;
4. Экран для проведения всех этапов измерения объемов партии бревен.
Данные экраны на платформе Android называются Activity[4] и содержат в себе не только элементы отображения и управления, но и информацию о родительском Activity, контейнер для передачи данных и положение в стеке вызовов Activity, который отвечает за отслеживание переключений между экранами. Переход между экранами может осуществляться несколькими методами класса текущего Activity.
Первый вариант перехода при помощи метода «startActivity» позволяет поместить Activity в стек вызовов и после завершения работы с ним произойдет обратный переход к предыдущему рабочему экрану.
Второй вариант перехода предусматривает наличие обратной связи между новым Activity и Activity-родителем. При такой схеме взаимодействия по завершению нового экрана происходит срабатывание события родителя «onActivityResult» с кодом завершения и данными переданными в специализированном контейнере. Такое взаимодействие позволяет очень четко регулировать передачу структурированных данных между экранами.
Однако контейнер данных поддерживает только несколько стандартных типов, таких как строка, целое число, число с плавающей точкой, время, дата и логическая переменная.
Возникает вопрос взаимодействия экранов при работе со сложными структурами данных, когда необходимо поддерживать рабочий цикл с данными на протяжении нескольких Activity. В данной ситуации отличным сценарием применения является шаблон
проектирования «Одиночка (Singleton)»[5],
Рис. 1 — Диаграмма класса менеджера измерений
В приложении создается класс менеджера измерений «RecognizeManager», который обеспечивает доступ до статического поля «report» экземпляром рабочего класса с данными измерения «ReportData». Схема данного класса представлена на рис 1. Класс «RecognizeManager» также гарантирует наличие в системе только одного экземпляра класса «ReportData» и для простоты взаимодействия обеспечивает сохранение текущего экземпляра класса измерений в хранилище при помощи метода «saveReport». Загрузка параметров измерения из хранилища по идентификатора осуществляется при помощи соответствующего метода «loadReport».
При таком подходе, если существует необходимость начать рабочий цикл с новым измерением, новый экземпляр класса «ReportData» не создается и не переопределяется, а только переопределяются поля текущего класса начальными значениями, либо очищаются в случае с вложенными контейнерами, такими как списки или словари. Данный механизм реализован в методе «newReport».
Методы работы с «ImageSeedData» предоставляют возможности взаимодействия с текущим изображением отчета на экране. Контроль текущего изображения осуществляется при помощи служебного поля «indexImageSeed», которое хранит индекс для связи с контейнером «image_seeds» класса «ReportData».
Стоит отметить что данный подход также обеспечивает целостность данных при возникновении критической ошибки на одном из рабочих экранов либо при автоматическом пересоздании рабочего экрана в другой ориентации при повороте устройства.
Изменения, произведенные с классом измерений, сохранятся благодаря менеджеру и могу быть снова восстановлены и отображены на экране измерений без потерь, либо в экстренном порядке сохранены в хранилище данных.
Рассмотрим подробнее структуру рабочего экрана измерений «RecognizeEditActivity». Во время работы приложения на данном рабочем экране находится сразу несколько элементов управления обеспечивающих взаимодействие с пользователем:
• плавающая кнопка действий;
• панель навигации с настройками измерений;
• панель инструментов с всплывающим меню.
Все эти элементы должны взаимодействовать друг с другом и реагировать на действия пользователя. Например, по нажатию плавающей кнопки должно происходит распознавание меток бревен в одном случае и удаление конкретной метки в другом.
В результате разработки исходный код событий, отлавливающих действия пользователя
у конкретных элементов начинает сильно разрастаться и перегружать общую картину рабочего цикла с экраном.
Для упрощения задачи дальнейшего сопровождения приложения предлагается использовать концепцию перехода рабочего экрана в некоторые состояния, которые заранее предопределяют свойства всех изменяющихся элементов экрана. Схема возможных состояний рабочего экрана представлена на рис. 2.
Исходным стоянием является начальный вид элементов управления при открытии Activity, когда не происходит никаких манипуляций с рабочей областью, а пользователю предлагается выбрать изображение с камеры или загрузить уже существующее из локального хранилища.
Рис. 2 — Состояния рабочего экрана
Следующее состояние отображает элементы управления работы с изображением и активирует этапы работы с измерением, такие как калибровка, распознание и сохранение. При переходе в состояние калибровки иконка плавающей кнопки сменяется на подтверждающую галочку, а при её нажатии происходит подтверждение выбранной области для калибровки.
Во время состояния распознавания все элементы управления становятся недоступными для пользователя, а в фоновом потоке запускается алгоритм автоматического распознавания меток бревен по контурам, при этом пользователю показывается диалоговое окно о процессе распознавания.
Заключительное состояние редактирования позволяет пользователю вручную добавлять метки бревен при помощи нажатия на плавающую кнопку с иконкой плюса. При выборе существующей метки экран переходить в состояние редактирования метки и пользователю предоставляются инструменты для перемещения метки, изменения размеров и удаления по нажатию на плавающую кнопку с иконкой корзины.
Менеджер состояний «OperationManager», организующий логику взаимодействия элементов управления и пользователя, содержит в себе контейнер соответствий каждого состояния и объекта с функцией переопределения свойств необходимых элементов управления, а также выполнения дополнительных действий работы с измерением. В данном классе метод смены состояния «зеЮрегайоп» принимает идентификатор операции и
вызывает соответствующий метод «work» у объекта, реализующего интерфейс «OperationWorker».
Данных подход проектирования сложного Activity разрабатываемого приложения при помощи менеджера состояний позволяет структурировать взаимодействие элементов управления друг с другом, обеспечить гибкость системы при добавлении новых функций или элементов управления, организовать пошаговое тестирование каждого состояния, что в свою очередь существенно облегчает поиск ошибок при разработке. Диаграмма классов рабочего экрана измерений, менеджера операций и контейнеров отчета представлена на рисунке 3.
За автоматическое распознавание объектов отвечает класс «NativeDetector», запускающий ресурсоемкую задачу определения параметров бревен в отдельном потоке для того, чтобы избежать зависания потока пользовательского интерфейса и приложения в целом.
Дальнейшие направления исследований включают в себя разработку автоматической отправки отчетов на электронную почту и разработку режима обучения, во время работы с которым приложение будет самостоятельно переключать состояния экрана измерения, показывая при этом пользователю доступный функционал всех элементов управления.
««Class»» SuperlV ; ScalelmageVlew
stroke.width : Float
onTouchEvent (event: MotionEvent): Boolean onReady (): Void onDraw (canvas: Canvas): Void drawCalibrator (canvas: Canvas): Void
■ drawTimber( canvas: Canvas, timber: TlmberData, select: Boolean) :Void notifyDataChange (): Void
< «Class»» OperationManager
operation ; Int
operations : ArrayMap<lnt, OperationWorker:»
i- OperationManager (}
h attachOperation ( oper: Int, worker: OperationWorker): Void r detachOperation (open Int): Void v setOperation £ oper: Int): Void i- getOperation (oper: Int): Void
«Class»
RecognizeEditActivity : AppCompatActivity
super Jv : SuperlV
operation_manager : OperationManager OPERATION.DEFAUIT : Int OPERATION.PARAMETRS : Int OPERATION LOAD : Int OPERATION_CALIBR : Int OPERATION.RECOGN : Int OPERATION EDIT : Int OPERATION,SAVE : Int
onCreate( state: Bundle): Void onCreateOptionsMenu (menu: Menu ): Boolean onBackPressed (): Void
onActivityResult (reqCode: lnt( resCode: Int data: Intent)
on Destroy (): Void
msgError (msg: String): Void
enableMenultems (): Void
disableMenultems (): Void
««Interface»» OperationWorker
«Class» NativeDetector : AsyncTask
bmp : Bitmap
imgView : SuperlV
timbers : ArrayList«TimberData>
v NativeDetector ( bmp: Bitmap, imgView: Superl onPreExecute (): Void dolnBackground ( params): Void onPostExecute (result): Void onCancelled (): Void
getDiameters ( nEllipse: NEllipse): FloatArray getAngle ( nEllipse: NEllipse): Float
«Object» Recognize Manager
report : ReportData indexImageSeed : Int
+ newReport (}: Void + setReportName (name: String): Name + saveReport (): Void + loadReport (id: Int): Void + gellmageSeed ( ): ImageSeed + setlmageSeed {index: Int): ImageSeed + addlmageSeed (path: String): Void + deletelmageSeed (): Void + deletelmageSeed (index: Int): Void + dearlmageSceds {): Void
«Class»
ReportData
- id : String
- name : String
- date : Date
■ image,seeds ArrayList< 1 mageSeedDa ta >
• ReportData ()
- getlD (): String
■ newReport {): Void
- getName (): String setName ( name: String ): Void
■ getDate (): Date
- getFormatDate {): String
• addlmageSeed {path: String): Void
- getlmageSeed (index: int): ImageSeedData
• deletelmageSeed {index: Int): Void
«Class» ImageSeedData
path : String
timbers : ArrayList<TimberData> étalon : Float ■ calib. method : Int calibr_object : FloatArray long_size ; Float
- ImageSeedData { path: String J
- getPath (): String addTimber (): Void
■ addTimber (timber: TlmberData ); Void
- getTimber (index: Int): TimberData
- getTimbers (): ArrayList<TimberData>
- dclctcTimbcr (index: Int): Void • dearTimbers (): Void
- getEtalon (): Float
- setEtalon (etalon: Float): Void
- getLongSize {): Float
- setLongSize (Isize: Float): Void
- getCalibrMethod {): Int setCalibrMethod (type: Int): Void
■ getCalibrObject {): FloatArray
- selCalibrObject( cobj: FloatArray): Void
«Class» TimberData
center : PointF diametrs : PointF angle : Float orient : Boolean
■ TimberData ()
- TimberData (center: PointF, diametrs: PointF)
• getCenter (}: PointF
- setCenter (center: PointF ): Void
• getDiametrs (): PointF
■ setDiametrs ( diametrs: PointF ): Void
- getAngle (}: Flaot
• setAngle {angle: Float): Void
- getOrient (): Boolean
■ setOrient (cornel: Boolean}: Void
Режим доступа:
Рис. 3 — Диаграмма зависимостей классов экрана измерений
Литература
1. Android. - [электронный ресурс]. - Режим доступа: https://android.com/
2. Android SDK Platform. - [электронный ресурс]. -
https://developer.android.com/studio/releases/platforms.html
3. Определение минимальной толщины трубки при помощи мобильных
приложений»/Естественные и технические науки. - [электронный ресурс]. - Режим доступа:
http://naukarus.com/opredelenie-minimalnoy-tolschiny-stenki-truby-pri-pomoschi-mobilnyh-
prilozheniy
4. Activity Component. - [электронный ресурс]. - Режим доступа:
https://developer.android.com/guide/components/activities.html?hl=ru
5. Singleton Pattern. - [электронный ресурс]. - Режим
https://www.tutorialspoint.com/design_pattern/singleton_pattern.htm
доступа: