|
|||||||||||||||||||||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Вопрос 4.7Как следует вызвать конструктор класса A, чтобы в результате выполнения кода была выведена на консоль строка в “ Конструктор A ”. class A{ A(int i){ System.out.print("Конструктор A"); } } public class Quest extends A{ public static void main(String[] args){ Quest s= new Quest(); //1 } public Quest(){ //2 } publicvoid show() { //3 } } 1) вместо //1 написать A(1); 2) вместо //1 написать super(1); 3) вместо //2 написать super(1); 4) вместо //2 написать A(1); 5) вместо //3 написать super(1). ПРОЕКТИРОВАНИЕ КЛАССОВ Шаблоны проектирования GRASP При создании классов, распределении обязанностей и способов взаимодействия объектов перед программистом возникает серьезная проблема моделирования взаимодействия классов и объектов. Представляются широкие возможности выбора. Неоптимальный выбор может сделать системы и их отдельные компоненты непригодными для поддержки, восприятия, повторного использования и расширения. Систематизация приемов программирования и принципов организации классов получила название шаблона. Основные принципы объектно-ориентированного проектирования, применяемого при создании диаграммы классов и распределения обязанностей между ними, систематизированы в шаблонах GRASP(General Responsibility Assignment Software Patterns). При этом были сформулированы основные принципы и общие стандартные решения, придерживаясь которых можно создавать хорошо структурированный Шаблон Expert При проектировании классов на первом этапе необходимо определить общий принцип распределения обязанностей между классами проекта, а именно: в первую очередь определить кандидатов в информационные эксперты – классы, обладающие информацией, требуемой для выполнения своей функциональности. Простые эксперты определять достаточно просто, но часто возникает необходимость дополнять класс атрибутами, и в этом случае необходимо сделать правильный выбор. Например, в подсистеме прохождения назначенного теста некоторому классу необходимо знать число вопросов, на которые получен ответ на текущий момент времени в процессе тестирования. Какой класс должен отвечать за знание количества вопросов, на которые дан ответ на текущий момент времени при прохождении теста, если определены следующие классы? /*пример # 1: шаблон Expert: LineRequestQuest.java:Test.java: Quest.java */ public class Test { //информационный эксперт private int idTest; private int numberQuest; private String testName; // реализация конструкторов и методов } public class LineRequestQuest { private int questID; // реализация конструкторов и методов } public class Quest { //информационный эксперт private int idQuest; private int testID; // реализация конструкторов и методов } Необходимо узнать количество вопросов из теста, на которые дан ответ, то есть число созданных объектов класса LineRequestQuest. Такой информацией обладает лишь экземпляр объекта Test, так как этот класс ответствен за знание общего количества вопросов в тесте. Следовательно, с точки зрения шаблона Expert объект Test подходит для выполнения этой обязанности, т.е. является информационным экспертом. /*пример # 2: шаблон Expert: Test.java */ сlass Test { private int idTest; private int numberQuest; private String testName; private int currentNumberQuest;
public int getCurrentNumberQuest() { // реализация }
// реализация конструкторов и методов } Рис. 5.1. Применение шаблона Expert Преимущества следования шаблону Expert: · сохранение инкапсуляции информации при назначении ответственности классам, которые уже обладают необходимой информацией для обеспечения своей функциональности; · уклонение от новых зависимостей способствует обеспечению низкой степени связанности между классами (Low Coupling); · добавление соответствующего метода способствует высокому зацеплению (Highly Cohesive) классов, если класс уже обладает информацией для обеспечения необходимой функциональности. Однако назначение чрезмерно большого числа ответственностей классу при использовании шаблона Expert может привезти к получению слишком сложных классов, которые перестанут удовлетворять шаблонам Low Coupling и High Cohesion. Шаблон Creator Существует большая вероятность того, что класс проще, если он будет большую часть своего жизненного цикла ссылаться на создаваемые объекты. После определения информационных экспертов следует определить классы, ответственные за создание нового экземпляра некоторого класса. Следует назначить классу B обязанность создавать экземпляры класса A, если выполняется одно из следующих условий: · класс В агрегирует (aggregate) объекты А; · класс В содержит (contains) объекты А; · класс В записывает или активно использует (records or closely uses) экземпляры объектов А; · классы B и A относятся к одному и тому же типу, и их экземпляры составляют, агрегируют, содержат или напрямую используют другие экземпляры того же класса; · класс В содержит или получает данные инициализации (has the initializing data), которые будут передаваться объектам А при его создании. Если выполняется одно из указанных условий, то класс В – создатель (creator) объектов А. Инициализация объектов – стандартный процесс. Грамотное распределение обязанностей при проектировании позволяет создать слабо связанные независимые простые классы и компоненты. В соответствии с шаблоном необходимо найти класс, который должен отвечать за создание нового экземпляра объекта Quest (агрегирующий экземпляры объектов Quest). Поскольку объект LineRequestQuest использует объект Quest, согласно шаблону Creator он является кандидатом для выполнения обязанности, связанной с созданием экземпляров объектов Quest. В этом случае обязанности могут быть распределены следующим образом: Рис. 5.2. Пример реализации шаблона Creator /* пример # 3: шаблон Creator: Qest.java: LineRequestQuest.java:Test.java */ public class Test { private int idTest; private int numberQuest; private String testName; private int currentNumberQuest; // реализация конструкторов и методов } public class LineRequestQuest { private int questID;
public void answerQuest() { // реализация Vector q = new Vector(); q.add(makeRequest(параметры)); // } public Quest makeRequest(параметры) { // реализация return new Quest(параметры); } } public class Quest{ private int idQuest; private int testID; public Quest() {} // реализация конструкторов и методов } Шаблон Creator способствует низкой зависимости между классами (Low Coupling), так как экземпляры класса, которым необходимо содержать ссылку на некоторые объекты, должны создавать эти объекты. При создании некоторого объекта самостоятельно класс тем самым перестает быть зависимым от класса, отвечающего за создание объектов для него. Распределение обязанностей выполняется в процессе создания диаграммы взаимодействия классов. Шаблон Low Coupling Степень связанности классов определяет, насколько класс связан с другими классами и какой информацией о других классах он обладает. При проектировании отношений между классами следует распределить обязанности таким образом, чтобы степень связанности оставалась низкой. Наличие классов с высокой степенью связанности нежелательно, так как: · изменения в связанных классах приводят к локальным изменениям в данном классе;
Пусть требуется создать экземпляр класса Quest и связать его с объектом Test. В предметной области регистрация объекта Test выполняется объектом Course. Рис. 5.3. Классы, которые необходимо связать Далее экземпляр объекта Course должен передать сообщение makeQuest() объекту Test. Это значит, что в текущем тесте были получены идентификаторы всех вопросов, составляющих тест и становится возможным создание объектов типа Quest и наполнение собственно теста. Рис. 5.4. Пример плохой реализации шаблона Low Coupling /* пример # 4: шаблон Low Coupling: Qest.java: Test.java: Course.java */ public class Course { private int id; private String name;
public void makeTest(){ Test test = new Test(параметры); // реализация while (условие){ Quest quest = new Quest(параметры); // реализация test.addTest(quest); } // реализация } } public class Test { // поля public void addTest(Quest quest){ // реализация } } public class Quest { // поля и методы } При таком распределении обязанностей предполагается, что класс Course связывается с классом Quest. Второй вариант распределения обязанностей с уклонением класса Course от создания объектов вопросов представлен на рисунке 5.5.
Рис. 5.5. Пример правильной реализации шаблона Low Coupling /* пример # 5: шаблон Low Coupling: Qest.java: Test.java: Course.java */ public class Course { private int id; private String name;
public void makeTest() { Test test = new Test(параметры); // реализация test.addTest(); // реализация } } public class Test { // поля public void addTest() { // реализация while (условие) { Quest quest = new Quest(параметры); // реализация } } } public class Quest { // поля и методы } Какой из методов проектирования, основанный на распределении обязанностей, обеспечивает низкую степень связанности? В обоих случаях предполагается, что объекту Test должно быть известно При использовании первого способа, когда объект Quest создается объектом Course, между этими двумя объектами добавляется новая связь, тогда как второй способ степень связывания объектов не увеличивает. Более предпочтителен второй способ, так как он обеспечивает низкую связываемость. В ООП имеются некоторые стандартные способы связывания объектов A и B: · объект A содержит атрибут, который ссылается на экземпляр объекта B; · объект A содержит метод, который ссылается на экземпляр объекта B, что подразумевает использование B в качестве типа параметра, локальной переменной или возвращаемого значения; · класс объекта A является подклассом объекта B; · B является интерфейсом, а класс объекта A реализует этот интерфейс. Шаблон Low Coupling нельзя рассматривать изолированно от других шаблонов (Expert, Creator, High Cohesion). Не существует абсолютной меры для определения слишком высокой степени связывания. Преимущества следования шаблону Low Coupling: · изменение компонентов класса мало сказывается на других классах; · принципы работы и функции компонентов можно понять, не изучая другие классы. Шаблон High Cohesion С помощью этого шаблона можно обеспечить возможность управления сложностью, распределив обязанности, поддерживая высокую степень зацепления. Зацепление – мера сфокусированности класса. При высоком зацеплении обязанности класса тесно связаны между собой, и класс не выполняет работ непомерных объёмов. Класс с низкой степенью зацепления выполняет много разнородных действий или не связанных между собой обязанностей. Возникают проблемы, связанные с тем, что класс: · труден в понимании, так как необходимо уделять внимание несвязным (неродственным) идеям; · сложен в поддержке и повторном использовании из-за того, что он должен быть использован вместе с зависимыми классами; · ненадежен, постоянно подвержен изменениям. Классы со слабым зацеплением выполняют обязанности, которые можно легко распределить между другими классами. Пусть необходимо создать экземпляр класса Quest и связать его с заданным тестом. Какой класс должен выполнять эту обязанность? В предметной области сведения о вопросах на текущий момент времени при прохождении теста записываются в объекте Course, согласно шаблону для создания экземпляра объекта Quest можно использовать объект Course. Тогда экземпляр объекта Course сможет отправить сообщение makeTest() объекту Test. За прохождение теста отвечает объект Course, т.е. объект Course частично несет ответственность за выполнение операции makeTest(). Однако если и далее возлагать на класс Course обязанности по выполнению все новых функций, связанных с другими системными операциями, то этот класс будет слишком перегружен и будет обладать низкой степенью зацепления. Этот шаблон необходимо применять при оценке эффективности каждого проектного решения. Виды зацепления: 1. Очень слабое зацепление. Единоличное выполнение множества разнородных операций. /*пример # 6: очень слабое зацепление: Initializer.java */ public class Initializer { public void createTCPServer(String port) { // реализация } public int connectDataBase(URL url) { // реализация } public void createXMLDocument(String name) { // реализация } } 2. Слабое зацепление. Единоличное выполнение сложной задачи из одной функциональной области. /*пример # 7: слабое зацепление: NetLogicCreator.java */ public class NetLogicCreator { public void createTCPServer() { // реализация } public void createTCPClient() { // реализация } public void createUDPServer() { // реализация } public void createUDPClient() { // реализация } } 3. Среднее зацепление. Несложные обязанности в нескольких различных областях, логически связанных с концепцией этого класса, но не связанных между собой. /*пример # 8: среднее зацепление: TCPServer.java */ public class TCPServer { public void createTCPServer() { // реализация } public void receiveData() { // реализация } public void sendData() { // реализация } public void compression() { // реализация } public void decompression() { // реализация } } 4. Высокое зацепление. Среднее количество обязанностей из одной функциональной области при взаимодействии с другими классами. /*пример # 9: высокое зацепление: TCPServerCreator.java: DataTransmission.java: CodingData.java */ public class TCPServerCreator { public void createTCPServer() { // реализация } } public class DataTransmission { public void receiveData() { // реализация } public void sendData() { // реализация } } public class CodingData { public void compression() { // реализация } public void decompression() { // реализация } } Если обнаруживается, что используется слишком негибкий дизайн, который сложен в поддержке, следует обратить внимание на классы, которые не обладают свойством зацепления или зависят от других классов. Эти классы легки в узнавании, поскольку они сильно взаимосвязаны с другими классами или содержат множество неродственных методов. Как правило, классы, которые не обладают сильной зависимостью с другими классами, обладают свойством зацепления и наоборот. При наличии таких классов необходимо реорганизовать их структуру таким образом, чтобы они по возможности не являлись зависимыми и обладали свойством зацепления. Шаблон Controller Одной из базовых задач при проектировании информационных систем является определение класса, отвечающего за обработку системных событий. При необходимости посылки внешнего события прямо объекту приложения, которое обрабатывает это событие, как минимум один из объектов должен содержать ссылку на другой объект, что может послужить причиной очень негибкого дизайна, если обработчик событий зависит от типа источника событий или источник событий зависит от типа обработчика событий. В простейшем случае зависимость между внешним источником событий и внутренним обработчиком событий заключается исключительно в передаче событий. Довольно просто обеспечить необходимую степень независимости между источником событий и обработчиком событий, используя интерфейсы. Интерфейсов может оказаться недостаточно для обеспечения поведенческой независимости между источником и обработчиком событий, когда отношения между этими источником и обработчиком достаточно сложны. Можно избежать зависимости между внешним источником событий и внутренним обработчиком событий путем введения между ними дополнительного объекта, который будет работать в качестве посредника при передаче событий. Этот объект должен быть способен справляться с любыми другими сложными аспектами взаимоотношений между объектами. Согласно шаблону Controller, производится делегирование обязанностей по обработке системных сообщений классу, если он: · представляет всю организацию или всю систему в целом (внешний контроллер); · представляет активный объект из реального мира, который может участвовать в решении задачи (контроллер роли); · представляет искусственный обработчик всех системных событий прецедента и называется Прецедент Handler (контроллер прецедента). Для всех системных событий в рамках одного прецедента используется один и тот же контролер. Controller – это класс, не относящийся к интерфейсу пользователя и отвечающий за обработку системных событий. Использование объекта-контроллера обеспечивает независимость между внешними источниками событий и внутренними обработчиками событий, их типом и поведением. Выбор определяется за- Раздутый контроллер (волшебный сервлет) выполняет слишком много обязанностей. Признаки: · в системе имеется единственный класс контроллера, получающий все системные сообщения, которых поступает слишком много (внешний или ролевой контроллер); · контроллер имеет много полей (информации) и методов (ассоциаций), которые необходимо распределить между другими классами. Шаблоны проектирования GoF Шаблоны проектирования GoF – это многократно используемые решения широко распространенных проблем, возникающих при разработке программного обеспечения. Многие разработчики искали пути повышения гибкости и степени повторного использования своих программ. Найденные решения воплощены «Любой шаблон описывает задачу, которая снова и снова возникает в нашей работе, а также принцип ее решения, причем таким образом, что это решение можно потом использовать миллион раз, ничего не изобретая заново». (Кристофер Александер). В общем случае шаблон состоит из четырех основных элементов: 1. Имя. Точное имя предоставляет возможно сразу понять проблему и 2. Задача. Область применения в рамках решения конкретной проблемы. 3. Решение. Абстрактное описание элементов дизайна задачи проектирования и способа ее решения с помощью обобщенного набора классов. 4. Результаты. Шаблоны классифицируются по разным критериям, наиболее распространенным из которых является назначение шаблона. Вследствие этого выделяются порождающие шаблоны, структурные шаблоны и шаблоны поведения. Порождающие шаблоны Порождающие шаблоны предназначаются для организации процесса создания объектов. К порождающим шаблонам относятся: Abstract Factory (Абстрактная Фабрика) – предоставляет интерфейс для создания связанных между собой объектов семейств классов без указания их конкретных реализаций; Factory (Фабрика) – создает объект из иерархического семейства классов на основе передаваемых данных (частный случай Abstract Factory); Builder (Строитель) – создает объект класса различными способами; Singleton (Одиночка) – гарантирует существование только одного экземпляра класса; Prototype (Прототип) – применяется при создании сложных объектов. На основе прототипа объекты сохраняются и воссоздаются, н-р путем копирования; Factory Method (Фабричный Метод) – определяет интерфейс для создания объектов, при этом объект класса создается с помощью методов подклассов. Шаблон Factory Необходимо определить механизм создания объектов по заданному признаку для классов, находящихся в иерархической структуре. Основной класс шаблона представляет собой класс, который имеет методы для создания одного объекта из нескольких возможных на основе передаваемых данных.
Рис. 5.6. Пример реализации шаблона Factory Решением проблемы может быть создание класса ClassFactory с одним методом getClassFromFactory(String id), возвращаемым значением которого будет ссылка на класс-вершину Base иерархии создаваемых классов. Программная реализация может быть представлена в общем виде следующим образом. /*пример # 10: создание объектов с помощью шаблона Factory: Base.java: First.java: Second.java: ClassFactory.java: Main.java */ package chapt05.factory; public abstract class Base { public abstract void perform(); } package chapt05.factory; public class First extends Base { public void perform() { System. out. println("First"); } } package chapt05.factory; public class Second extends Base { public void perform() { System. out. println("Second"); } } package chapt05.factory; public class ClassFactory { private enum Signs { FIRST, SECOND } public static Base getClassFromFactory(String id) { Signs sign = Signs. valueOf (id.toUpperCase()); switch (sign){ case FIRST: return new First(); case SECOND: return new Second(); default: throw new EnumConstantNotPresentException( Signs. class, sign.name()); } } } package chapt05.factory; public class Main { public static void main(String args[]) { Base ob1 = ClassFactory. getClassFromFactory ("first"); Base ob2 = ClassFactory. getClassFromFactory ("second"); ob1.perform(); ob2.perform(); } } Один из примеров применения данного шаблона уже был рассмотрен в примере # 5 предыдущей главы. Шаблон AbstractFactory Необходимо создавать объекты классов, не имеющих иерархической связи, но логически связанных между собой. Абстрактный класс-фабрика определяет общий интерфейс таких фабрик. Его подклассы обладают конкретной реализацией методов по созданию разных объектов. Предложенное решение изолирует конкретные классы. Так как абстрактная фабрика реализует процесс создания классов-фабрик и саму процедуру инициализации объектов, то она изолирует приложение от деталей реализации классов. Одна из возможных реализаций шаблона предложена в следующем примере. Классы фабрики создаются по тому же принципу, по которому в предыдущем шаблоне создавались объекты. /*пример # 11: создание классов-фабрик по заданному признаку: AbstractFactory.java */ package chapt05.abstractfactory; public class AbstractFactory { enum Color { BLACK, WHITE }; public static BaseFactory getFactory(String data) { Color my = Color.valueOf(data.toUpperCase()); switch (my){ case BLACK: return new BlackFactory(); case WHITE: return new WhiteFactory(); Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.053 сек.) |