480 likes | 623 Views
Тема 4 . Структурни диаграми по UML 2.0. Структурни диаграми. Зависимости; Имплементиране на зависимости; Агрегация и композиция ; Съвместно използване на моделите ; Имплементиране на композицията ; Имплементиране на агрегация ; Интерфейси ; Имплементиране на интерфейси;
E N D
Структурни диаграми • Зависимости; • Имплементиране на зависимости; • Агрегация и композиция; • Съвместно използване на моделите; • Имплементиране на композицията; • Имплементиране на агрегация; • Интерфейси; • Имплементиране на интерфейси; • Предефиниран интерфейс Ipersistent; • Имплементиране на интерфейсите.
Зависимости Същност: Зависимост между елементи на ООП съществува ако промяната на дефиницията на единия елемент води до промяна на свързания (зависим) елемент.
Имплементиране на зависимости Имплементиране: Не е необходимо да се имплементират по специален начин зависимостите. Те се отразяват на кода, който се създава към конкретния клас. Например, в кода на студента зависимост има при класа CPerson в който има валидизиращ клас, служещ за проверка на ЕГН. Тази зависимост в класа не е нужно да се създава чрез собствен клас. Това може да се отрази в методите на класа, като се създаде валидизиращ метод-логическа проверка за валидност на низа (ЕГН). Методът се вгражда в класа. Той може да е статичен метод на класа, връщащ логически резултат. Ако ЕГН е валиден – true, иначе false.
Имплементиране на зависимости abstract class CPerson { private class Sex { static final int Male=0; static final int Female=1; } private String m_strName; private int m_Sex; private String m_egn; private CAddress m_address; public CPerson(String Name, String egn) throws Exception { m_strName=Name; int iSex=Integer.valueOf(egn.substring(8,9).toString()); if((iSex%2)!=0){ m_Sex=Sex.Female; } else{ m_Sex=Sex.Male; } if(ValidateEGN(egn)) m_egn=egn; else throw new Exception("Invalid EGN..."); } // зависимости public static boolean ValidateEGN(String strEGN) { // анализиране на параметъра и определяне на валидността по алгоритъм за // проверка return true; } }
Имплементиране на зависимости Примерна реализация на метода за проверка на ЕГН: abstract class CPerson { ///............ // зависимости public static boolean ValidateEGN(String strEGN) { if(strEGN.length()!=10) return false; int iyear=Integer.valueOf(strEGN.substring(0,2)); int imonth=Integer.valueOf(strEGN.substring(2,4)); int iday=Integer.valueOf(strEGN.substring(4,6)); // ToDo… Validate iyear, imonth, iday values by Date class check if(imonth>12){ imonth-=40; if(imonth<0) imonth+=20; } if(imonth<1||imonth>12) return false;
Имплементиране на зависимости int iSex=Integer.valueOf(strEGN.substring(8,9)); if((iSex%2)!=0 && m_Sex==Sex.Male) return false; else{ if((iSex%2)==0 && m_Sex==Sex.Female) return false;} int icheck=(Integer.parseInt(strEGN.substring(0,1))*2); icheck+=Integer.valueOf(strEGN.substring(1,2))*4; icheck+=Integer.valueOf(strEGN.substring(2,3))*8; icheck+=Integer.valueOf(strEGN.substring(3,4))*5; icheck+=Integer.valueOf(strEGN.substring(4,5))*10; icheck+=Integer.valueOf(strEGN.substring(5,6))*9; icheck+=Integer.valueOf(strEGN.substring(6,7))*7; icheck+=Integer.valueOf(strEGN.substring(7,8))*3; icheck+=Integer.valueOf(strEGN.substring(8,9))*6; icheck=icheck%11; if(icheck==10) icheck=0; int iTest=Integer.valueOf(strEGN.substring(9,10)); if(icheck!=iTest) return false; return true; } }
Агрегация и композиция Дефиниции: • Агрегация е асоциации от типа “е част от”. Обектът от “част” може да остане да съществува и без обекта “цяло”. • Композиция е строга форма на агрегация, при която цялото е в неделима връзка с частта и между него и цялото се се формира тип отношение “е съставен от”. Всеки обект “част” се асоциира с един обект от “цяло”.
Агрегация и композиция Примери: Самолетът е съставен от двигател(и), ... Двигателят е част от самолета. (композиция) 1 1..* Пратката се състои от пакети. Пакетът е част от пратката. (агрегация) 1 1..* Групата се състои от студенти. Студентът е част от групата си. (агрегация) 0..* 1..* Групата се състои от групи в ролята на подгрупа. Подгрупата е част от групата си. Рекурсивно дефиниране 0..1 0..*
Агрегация и композициямултипликатори Мултипликатори: • Пакетът е част от една и само една пратка. • Пратката се образува от един или повече пакети • Двигателят е част от един и само един самолет. • Един самолет има един или повече двигатели. • Един студент може да е член на една или повече групи. • Групата може да се състави от един или повече студента. • Всяка група може да е част от по-голяма група. • Групата може да се изгради от по малки подгрупи.
Моделиране на агрегацията(състав) Формална дефиниция: Цялото се съставено от елементи (части). Елементът (част) е част от цялото. UML диаграмите за моделиране на агрегацията са самостоятелни, въпреки близостта им с асоциацията. Това е така поради широкото разпространение на този вид отношение в практиката. Символизира се с ромб, насочен към класа цяло. Поради това, че е вид асоциация, тя се маркира по подобен начин като асоциацията-с етикет, мултипликатор и роли. Допуска се липса на мултипликатор от страната на цялото, като в този случай се подразбира 1.
Имплементиране на агрегацията (състав) Най-често агрегацията (състав) се имплементира с инстанция на променлива от друг клас в класа. Разликата със съвкупността (композиция) е в принципите на унищожаване на класа. При състав класът трябва да се унищожава при унищожаване на заграждащия го клас.
Правила за разграничаване на агрегацията • Трябва да е смислена фразата “тази част е част от цялото”; • Частта трябва да е част от универсума. Тя трябва да има собствени атрибути и методи; Примери: • двигателят е част от самолета; • студентът е част от групата си ; • длъжността част ли е от служителя? => асоциация • Частта трябва да е съществена за цялото към което се отнася. Ако частта е от универсума, но ако не е съществена при разглеждане на текущата абстракция, представена чрез класа, тя не трябва да се моделира към него. Примери: Самолет – двигател в различни приложения. • Агрегацията е вид асоциация и има мултипликатори и роли. По същия начин, както при асоциациите, при агрегацията има обозначение на тези елементи; • Агрегацията се наследява. Както при асоциациите, тя се моделира с комбинация от атрибути и методи на класовете. По същия начин тя се наследява при класова йерархия;
Особености на композицията Агрегация (състав) и композиция (съвкупност) дефинират отношение между два класа в класова йерархия, определящо връзка между два класа от тип „е част от“ . И двата се имплементират с инстанция на променлива от друг клас в класа. Разлика: При композиция (съвкупност) класът не се унищожава при унищожаване на заграждащия го клас.
Имплементиране на агрегацията и композиция Използване на йерархиите за изграждане на дефинициите на даден клас: 1. Чрез включване на клас във вътрешността на друг клас: Примери: • диалогов контрол на потребителски интерфейс може да съдържа прости контроли, като бутони, списъчни контроли, редактиращи полета и др. Тези контроли са част от диалоговия контрол и се включват в неговия клас; • страниците, които са част от книга.
Имплементиране на агрегацията и композиция 2. Чрез преобразуване на съществуващи обобщени класове и тяхното наследяване: • Например,диалогов клас може да се разглежда като специализиран вариант на по-общия клас прозорец. Специализираният клас може автоматично да използва атрибутите на по-общия клас- големина, позиция и други и може евентуално да добави нови атрибути и поведение към него, например свързаните към него обекти контроли. Такъв вид йерархия е наследяването.
Съвместно използване на моделите Обща схема, съдържаща класови йерархии, асоциация, агрегация и композиция:
Съвместно използване на моделите Видове класови йерархии в схемата: • Асоциациите по принцип описват отношения между самостоятелни (независими класове):
Съвместно използване на моделите • Класовете библиотека (Library) и читател (Reader) са в асоциацията, която е зависима (се управлява от клас) - Class C. В примера класът, управляващ асоциацията е заемане (Borrowing). Могат да се налагат ограничения за броя на заетите книги, например 0..4 (до 4 книги):
Съвместно използване на моделите Агрегация (Aggregation) и Композиция (composition) описват отношения между несамостоятелни (зависими класове), между които има зависимост от типа част/цяло,определяно с думата от естествен език “има”. В примерната схема агрегации са отношенията: • Книга и библиотека; • Читател и библиотека; • Заемане и библиотека;
Съвместно използване на моделите В примерната схема в композиция е отношението между книга и страница. Самата библиотечна книга участва в агрегация към библиотеката. Библиотеката може да съществува и без книгите (заети са) всичките, книгата не може да съществува без страниците си (те са неразделна част) от книгата:
Съвместно използване на моделите • В основата на йерархията са два основни класа- Book и Student. Всеки от тях описва общи обекти, притежава общи атрибути за всички обекти, които ще ги наследят. • Book е базов клас на библиотечната книга; • Student е базов клас за всички читатели на студентската библиотека, които го наследяват; • Reader е специализиран студент, който използва студентската библиотека. Обектът съдържа атрибути, като списък на заетите книги, например checkedBooks ArrayList; • Книгата се състои от (е композицияот) страници (клас Page). Композицията показва, че книгата може да има 1 или повече страници. Част от методите на Book трябва да работят със страниците, които се имплементират в класа Book и са достъпни за наследниците на класа. • Класът LibraryBook е специализиран клас на Book и като такъв има допълнителни атрибути, например дата на придобиване, статус (заета/незаета- borrowingStatus boolean), идентификационен номер, който използват при търсене в библиотеката и други.
Съвместно използване на моделите • Borrowing се използва за имплементиране на асоциацията между читател и книга в библиотеката. Прекъснатата линия в описанието на UML показва тази релация чрез класа Borrowing. В простия случай връзката се маркира чрез етикет (обозначение на двойната релация). Използването на клас означава, че асоциацията (връзката) между класовете се управлява от класа; • Между класовете Library и LibraryBook има отношение агрегация, което означава, че при унищожаването на класа, който съдържа в себе си Съвкупност (aggregation) елементът не се унищожава от това. “При унищожаване на библиотеката, книгите, които са били в нея се запазват”; • Между класовете Page и Book има отношение състав (композиция composition ), което означава неделимост в организацията на елементите. “При унищожаване на книгата се унищожават и страниците, от които тя се състои”.
Кодиране на композицията между страница и книга • Реализация на композиция чрез код на Java import java.util.ArrayList; class Page { private int pageNum; private String pageContent; public Page(){ pageNum =1; } public Page(String write, int page ){ pageContent = write; pageNum=page; } public String getContent() { return pageContent; } public int getPageNum() { return pageNum; } public void setContent(String write, int page) { pageContent = write; pageNum=page; } }
Кодиране на композицията между страница и книга Композиция на книга от страници public class Book { // композиция на страниците елементи (части) // в множество книга ( цяло ) с мултипликатор 1..* private ArrayList pages; // имплементация чрез списък // номер на старницата е индекса в списъка // съдържанието е низ от символи public Book() { // default constructor pages = new ArrayList(1); // осигуряване на 1..* pages.add(0, "Book Title" ); // съдържание на корицата } public Book(int numP) { // експлицитен по брой страници pages = new ArrayList(numP); }
Кодиране на композицията между страница и книга // вмъкване на страница public void insertPage( int pageNum, String pageContent ) { try { pages.add(pageNum, pageContent ); } catch(IndexOutOfBoundsException e) { } } // добавяне на страница в края public void insertPage( String pageContent ) { pages.add(pageContent); }
Кодиране на композицията между страница и книга // промяна на съдържание на страница public void replacePage( int pageNum, String pageContent ) { try { pages.set(pageNum,pageContent); } catch(IndexOutOfBoundsException e) { } }
Кодиране на композицията между страница и книга // изтриване на страница без корицата (0) public void deletePage( int pageNum ) { try{ pages.remove(pageNum); if(pages.size()>0) super.setContent(pages.get(pageNum-1).toString(),pageNum-1); else //премахва само съдържанието на корицата (0) super.setContent("", 0); } catch (IndexOutOfBoundsException e){ } }
Кодиране на композицията между страница и книга // изтриване на страница включващо и корицата /* !!!! кодът да се използва само при 0..* public void deletePage( int pageNum ) { try{ pages.remove(pageNum); } catch (IndexOutOfBoundsException e){ } } */
Кодиране на композицията между страница и книга // размяна на страници public void exchangePages( int pageNumFrom, int pageNumTo ) { try { Object fromText = pages.remove(pageNumFrom); Object toText = pages.set( pageNumTo, (String)fromText); pages.add(pageNumFrom,toText.toString()); } catch( IndexOutOfBoundsException e ) { } } // връщане на списъка страници public ArrayList getPages() { return pages; }
Кодиране на композицията между страница и книга // тестова програма public static void main(String[] args) { Book myBook = new Book(); for(int i = 0; i < myBook.getPages().size() ; i++) { System.out.println( myBook.getPages().get( i ) ); } System.out.println("Initial content"); myBook.insertPage("1"); myBook.insertPage("2"); myBook.insertPage("3"); myBook.insertPage("4"); myBook.insertPage("5"); myBook.insertPage("6"); myBook.insertPage("7"); myBook.insertPage("8"); myBook.insertPage("9"); myBook.deletePage( 7 ); myBook.insertPage( 2, "31" ); myBook.insertPage( 4, "41" ); myBook.insertPage( 6, "51" ); myBook.exchangePages( 6, 1 ); for(int i = 0; i < myBook.getPages().size() ; i++) { System.out.println( myBook.getPages().get( i ) ); } } // main } // край на класа
Kодиране на агрегация import java.util.*; public class Library { private ArrayList<LibraryBook> books = new ArrayList<LibraryBook>(); // list of library books private ArrayList<Borrowing> borrowing = new ArrayList<Borrowing>(); // list of borrowing private ArrayList<Reader> reader = new ArrayList<Reader>(); // list of readers public ArrayList<Borrowing> getBorrowing() { return borrowing; } public ArrayList<LibraryBook> getBooks() { return books; } public ArrayList<Reader> getReaders() { return reader; } public void addReader( Reader rdr ) { reader.add(rdr); }
Kодиране на агрегация //return Reader FN public String findReader(Reader toFind ) { boolean res = reader.contains(toFind); if(res) return toFind.GetFN(); else return null; } //return book ID public String findBook(LibraryBook toFind ) { boolean res = books.contains(toFind); if(res) return toFind.GetID(); else return null; }
Kодиране на агрегация public static void main(String[] args) { Library oLib = new Library(); Reader oRd = new Reader("reader1", "046050"); oLib.getReaders().add(oRd); oRd.setLibrary(oLib); … oLib.getBooks().add(new LibraryBook("ID1")); …. Object[] arr = oLib.getReaders().toArray(); for(int i=0; i<arr.length; i++) System.out.println(arr[i].toString()); arr = oLib.getBooks().toArray(); for(int j=0; j<arr.length; j++) System.out.println(arr[j].toString()); String res = oLib.findReader(new Reader("reader3", "046052")); System.out.println(res); res = oLib.findBook(new LibraryBook("ID5")); System.out.println(res); } }
Kодиране на агрегация public class CCourse { private HashSet exams; //...... public HashSet getExams() {return exams; } private void setExams(HashSet ex) {exams = ex; } // aggregation course <=> seminars //Премахване на courseКурсът и неговите семинари се премахват public void remove() { if(exams !=null) { //оригиналът се копира, защото не се допуска //изтриване на елементите на колекцията по //време на итерирването HashSet set = (HashSet) getExams().clone(); Iterator iterator = set.iterator(); // премахване на упражненията на курса while(iterator.hasNext()) { CExams exam = (CExams)iterator.next(); getExams().remove(exam); } } // Премахване на инстанцията от записващата среда!!!! } //...... }
Интерфейси Определение: Интерфейса е дефиниция на сувкупност от един или повече методи и нула или повече атрибути. Предназначение: Интерфейсите служат за дефиниция на множество от поведения на обект от даден клас. Те се имплементират чрез класове или компоненти. За да имплементира един интерфейс, класът трябва да включва в себе си дефиниция на метод(ите) дефинирани в интерфейса.
Интерфейси Пример за интерфейс Даден е класът Student имплементиращ интерфейса Serializable и Searchable. За да се имплементира интерфейса Searchable, Student трябва да включва метод, наречен find, с параметър критерия за търсене. Има 2 начина за представяне на интерфейсите чрез структурни диаграми:
Структурни диаграми на интерфейсите Диаграма на примерния интерфейс
Правила за имплементиране на интерфейсите • Интерфейсите се декларират като класовете. Разликата е използването на ключовата дума interface вместо class . Както класовете и интерфейсите могат да са наследници на нула или повече други интерфейси с ключовата дума extends. Това е единственият начин (ограничен) чрез който в Java може да се реализира множествено наследяване. • Документирането им е като на класовете. • Дефинициите не включват тяло с код. Целта е да се дефинира множество от декларации (сигнатури) на методите, не и тяхната същинска имплементация (тяло на методите). • В интерфейсите на Java може да има атрибути, но те трябва да се декларират static, които са фактически именовани константи, те не могат да се променят.
Правила за имплементиране на интерфейсите Пример: public interface Months { (static) int JANUARY = 1, FEBRUARY = 2, MARCH = 3, APRIL = 4, MAY = 5, JUNE = 6, JULY = 7, AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10, NOVEMBER = 11, DECEMBER = 12; } В интерфейсите могат да се дефинират и статични класове, в които да се дефинират методи;
Правила за имплементиране на интерфейсите Пример интерфейс с клас : public interface GlobalData { public class FileGlobalData { public void getArray(ArrayList<String> Data) { String str; try { RandomAccessFile fin = new RandomAccessFile("<път до файла> \\input.txt","r"); while((str = fin.readLine()) != null ) { Data.add(str.trim().toLowerCase()); } fin.close(); } catch(EOFException e) { System.out.println("End of file encountered"); } catch(FileNotFoundException e) { System.out.println("FileNotFound"); } catch(IOException e) { System.out.println("IOException encountered"); } } } }
Правила за имплементиране на интерфейсите Клас за предаване на глобални данни и зареждането им от интерфейса GlobalData: import java.util.ArrayList; public class MyClass { static final int lSize=400000; static private ArrayList<String> Data=new ArrayList<String>(MyClass.lSize); MyClass() { GlobalData.FileGlobalData fc = new GlobalData.FileGlobalData(); fc.getArray(Data); } public static void main(String[] args) { System.out.println("File loading... "); MyClass oMyClass = new MyClass(); int iSize = FileTest.Data.size(); // брой прочетени низове System.out.println("Loaded... "); } finally{ // код за обработка на неприхванати грешки }; }
Имплементиране на интерфейсите Предефиниран интерфейс Ipersistent: Операции: • Премахване на обект от записващата среда. Синтаксис: boolean remove(); Изисквания: • Обектът не бива повече да е достъпен за другите обекти; • Премахването не е задължително изтриване на обекта. То може да означава неговото архивиране; • Запис на обекта в записващата среда. Изисква обектът да се запише. Синтаксис: void save(); • Създаване на обект от записваща среда. Синтаксис: void retrieve(); Изисквания: • Обектът не се съдържа задължително в записващата среда; • Ако обектът съществува в записващата среда, трябва да се създаде в паметта;
Предефиниран интерфейс IPersistent public interface IPersistent { /** * Премахване на обект от записващата среда */ boolean remove(); /** * Запис на обекта в записващата среда */ void save(); /** * Създаване на обект от записваща среда */ void retrieve(); }
Предефиниран интерфейс IPersistent Пример: abstract public class Seminar implements IPersistent { public boolean remove() { // имплементация return true; } public void save() { // имплементация } public void retrieve() { // имплементация } .... }
Интерфейс IPersistent Кодове за реализация на IPersistent: /** * * Премахване на Seminar от записващата среда * * @postcondition Обектът Seminar не бива повече да е достъпен за другите обекти * */ public boolean remove() { if (instructors != null) { // Асоциация на Seminar с водещите преподаватели Vector instructorList = instructors.elements(); while (instructorList.hasMoreElements()) { Professor professor = (Professor)instructorList.nextElement(); professor.removeSeminar(this); } } // // Асоциация на Seminar с курс // if (getCourse() != null) { getCourse.removeSeminar(this); setCourse(null); } // Специфичен за записващата среда код по премахването => връща резултат от записването }
Интерфейс IPersistent /** * Запис на Seminar в записващата среда * * @postcondition Seminar е записан в записващата среда */ public void save() { // Специфичен за записващата среда код } /** * Създаване на Seminar от записваща среда * @precondition None. Seminar не се съдържа задължително в записващата среда. * @postcondition Ако Seminar съществува в записващата среда, трябва да се се създаде в паметта. */ public void retrieve() { // Специфичен за записващата среда код за четене и създаване на Seminar }