Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Проектирование АИС.pdf
Скачиваний:
250
Добавлен:
05.06.2015
Размер:
3.32 Mб
Скачать

0.2.2 Первоначальная постановка задачи

Объектная модель и её реализация

Диаграмма прецедентов содержит только один прецедент “Поиск в телефонном справочнике”. Поиск должен осуществляться по подразделениям (подотделам), сотрудникам и телефонам.

Диаграмма классов значительно сложнее.

Класс Collaborator имеет атрибуты:

code — код сотрудника, это необходимо при одинаковых “ФИО” сотрудников или, например, при изменении фамилии сотрудника;

family — фамилия;

name — имя;

patronym — отчество.

Операции класса это:

__init__ — конструктор класса, в данном случае он необходим поскольку его атрибуты нужно инициализировать;

__hash__ — определение этой функции позволяет использовать объект класса в качестве элемента словарей и множеств;

__eq__ — поскольку хэш представляет отображение элементов некоторого множества в конечное множество чисел, обычно это числа умещающиеся в машинное слово, то необходимо разрешать так называемые коллизии. В случае коллизии два разных объекта имеют одинаковое значение функции __hash__ и __eq__ позволяет различить эти объекты.

Подразделения представлены классом Subdivision, который имеет следующие атрибуты:

name — название подразделения;

collaborators — множество его сотрудников;

subdivisions — множество его собственных подразделений.

Операции класса это также состоят из конструктора, операций __hash__ и __eq__ поскольку подразделение может быть в качестве элемента множества subdivisions, а также других операций:

__iter__ — итератор для просмотра всех сотрудников подразделения, включая и сотрудников его собственных подразделений;

add — для добавления сотрудника к подразделению;

addSubdivision — для добавления к подразделению другого подразделения в качестве его собственного подразделения;

iterSubdivision — итератор для просмотра его собственных подразделений.

Оставшиеся элементы диаграммы классов могут быть описаны кратко. TelephoneType определяется своим названием. TelephoneTypes представляет собой множество из объектов класса TelephoneType. Класс Telephone состоит из номера и его типа. Телефоны содержаться в множестве задаваемым классом Telephones. Телефонный справочник содержит TelephoneRecord ссылающийся на телефоны и подразделения.

Рассмотрим реализацию телефонного справочника . Для усвоения использованного ниже материала необходимо усвоить 1-4 лекции курса “Учебный курс - Язык программирования Python” [10] Сузи Романа Арвиевича.

1 # -*- coding: utf-8 -*-

2

3 """

4 Телефонная книга организации

5 """

6

7 import itertools

8

9 class Collaborator:

10"""

11Сотрудник

12"""

13def __init__(self, code, family, name, patronym):

14self.code = code

15self.family = family

16self.name = name

17self.patronym = patronym

19def __str__(self):

20return "%s %.2s. %.2s." % (self.family, self.name, self.patronym)

22def __hash__(self):

23return hash(self.code)

24

25def __eq__(self, other):

26return self.code == other.code

Строка 1 определяет используемую кодировку. Затем, нам строках 3-5, определяем документацию нашей программы. На 7 строке импортируем модуль itertools для организации итераторов для обхода подразделения по его сотрудникам и по его собственным подразделениям. Далее следует описание

класса Collaborator. При вычисление хэш используется стандартная hash функция языка Python.

28class Subdivision:

29"""

30Подразделение

31"""

32def __init__(self, name):

33self.name = name

34self.collaborators = set()

35self.subdivisions = set()

37def __hash__(self):

38return hash(self.name)

39

40def __eq__(self, other):

41return self.name == other.name

43def __iter__(self):

44i = iter(self.collaborators)

45for s in self.subdivisions:

46i = itertools.chain(i, iter(s))

47

return i

48

 

49def add(self, collaborator):

50assert collaborator not in self

51self.collaborators.add(collaborator)

53def addSubdivision(self, subdivision):

54assert subdivision not in self.subdivisions

55assert not set(self).intersection(set(subdivision))

56self.subdivisions.add(subdivision)

57

58def iterSubdivision(self):

59i = iter(self.subdivisions)

60for s in self.subdivisions:

61i = itertools.chain(i, s.iterSubdivision())

62return i

ВSubdivision для организации итераторов __iter__ и iterSubdivision используется так называемое зацепление итераторов. Операция add на строчке 50 запрещает добавлять сотрудника к подразделению если он есть в нем или в его собственном подразделении. Это достигается за счет переопределения стандартного метода __iter__ для контейнера языка Python. Строчка 54 запрещает добавлять подразделение если там оно уже есть, а строчка 55 если в нем есть хотя бы один сотрудник уже имеющиеся в нашем подразделении.

64class TelephoneType:

65"""

66Тип телефона

67"""

68def __init__(self, name):

69self.name = name

70

71def __hash__(self):

72return hash(self.name)

73

74def __eq__(self, other):

75return self.name == other.name

Тип телефона определяется его именем.

77class TelephoneTypes(set):

78"""

79Типы телефонов

80"""

81def add(self, telephoneType):

82assert telephoneType not in self

83set.add(self, telephoneType)

На строке 82 стоит запрет на добавление к множеству типов телефонов элемента если он там уже есть.

85class Telephone:

86"""

87Телефон

88"""

89def __init__(self, telephone, telephoneType):

90self.number = telephone

91self.type = telephoneType

92

93def __hash__(self):

94return hash(self.number)

95

96def __eq__(self, other):

97return self.number == other.number

Телефон определяется его типом и номером.

99class Telephones(set):

100"""

101Телефоны

102"""

103def __init__(self, telephoneTypes):

104set.__init__(self)

105self.telephoneTypes = telephoneTypes

107def add(self, telephone):

108assert telephone not in self

109assert telephone.type in self.telephoneTypes

110set.add(self, telephone)

На строке 108 стоит запрет на добавление к множеству телефонов элемента с уже существующим номером или и на строке 109 если его типа нет в telephoneTypes.

112class TelephoneRecord:

113"""

114Запись в телефонном справочнике

115"""

116def __init__(self, telephone, collaborator):

117self.telephone = telephone

118self.collaborator = collaborator

119

120def __hash__(self):

121return hash((self.telephone, self.collaborator))

123def __eq__(self, other):

124return self.telephone == other.telephone and \

125

self.collaborator == other.collaborator

Запись в телефонном справочнике должна ссылаться на телефон и сотрудника.

127class TelephoneDir(set):

128"""

129Телефонный справочник

130"""

131def __init__(self, telephones, subdivision):

132set.__init__(self)

133self.telephones = telephones

134self.subdivision = subdivision

135

136def add(self, telephoneRecord):

137assert telephoneRecord.telephone in self.telephones

138assert telephoneRecord.collaborator in self.subdivision

139assert telephoneRecord not in self

140set.add(self, telephoneRecord)

На строке 137 стоит запрет на добавление к множеству телефона, если его нет среди телефонов справочника. Аналогично, на строке 138, запрет для подразделений. Строка 139 запрещает добавлять записи в телефонный справочник, если они уже там есть.

142 if __name__ == ’__main__’: 143 import tdcsv

144

145 telephoneDir = tdcsv.load()

146

147for s in telephoneDir.subdivision.iterSubdivision():

148if s.name == ’помощник проректора’:

149for r in telephoneDir:

150if r.collaborator in s and r.collaborator.family.find(’ск’) >= 0:

151print r.telephone.number, "%s %s. %s."% \

152

(r.collaborator.family, r.collaborator.name[:2],

r.collaborator.patronym[:2]) 153 break

154

155for s in telephoneDir.subdivision.iterSubdivision():

156if s.name == ’зав. кафедрой’:

157for r in telephoneDir:

158if r.collaborator in s and r.collaborator.family.find(’сс’) >= 0:

159print r.telephone.number, "%s %s. %s."% \

160

(r.collaborator.family, r.collaborator.name[:2],

r.collaborator.patronym[:2]) 161 break

Каждый модуль языка Python может быть использован в качестве головного, в этом случае значение переменной __name__ будет иметь значение ’__main__’ (см. строку 142).

На 143 строке подключаем модуль импорта данных из формата CSV, а на 145 осуществляется сам импорт.

На строчках 147–153 осуществляется поиск в подразделении помощник проректора сотрудника, фамилия которого содержит ск.

На строчках 155–161 осуществляется поиск, аналогичный предыдущему, в подразделении зав.

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

51-57-39 Виноградский С. Г.

51-18-84 Лосатинская А. С.

В результате первый запрос вернул два телефона, а второй не одного.

CSV

Для усвоения материала необходимо ознакомится с 7 курса “Учебный курс - Язык программирования Python” [10] Сузи Романа Арвиевича.

Для представления информации используется два файла subdivision.csv

и ssu.csv

со струк-

турой колонок представленных на рисунке ниже.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ssu

 

 

 

 

 

 

 

телеф

 

 

 

 

 

 

код сот

 

 

 

subdivision

 

 

 

 

 

 

 

фамил

 

 

 

подразделен

 

 

 

 

 

 

 

головное подразделен

 

и

 

 

 

 

 

 

отчест

 

 

 

 

 

 

 

 

 

 

 

 

подразделен

 

 

 

 

 

 

тип те

 

 

Для набора можно воспользоваться любым текстовым редактором поддерживающим кодировку UTF8 или экспортом из электронных таблиц.

Сначала опишем функцию load из файла tdcsv.py для загрузки данных из формата CSV.

30def load():

31subdivision = {}

32for rec in csv.reader(open(os.path.join(os.curdir, ’subdivision.csv’), ’rb’), delimiter=’;’):

33subdivision[rec[0]] = telephonedir.Subdivision(rec[0])

34if rec[1]:

35subdivision[rec[1]].addSubdivision(subdivision[rec[0]])

36else:

37telephoneDir =

telephonedir.TelephoneDir(telephonedir.Telephones(telephonedir.TelephoneTypes()), subdivision[rec[0]])

38

39telephones, telephoneTypes, collaborators = {}, {}, {}

40for rec in csv.reader(open(os.path.join(os.curdir, ’ssu.csv’), ’rb’), delimiter=’;’):

41if rec[6] not in telephoneTypes:

42telephoneTypes[rec[6]] = telephonedir.TelephoneType(rec[6])

43telephoneDir.telephones.telephoneTypes.add(telephoneTypes[rec[6]])

44if rec[0] not in telephones:

45telephones[rec[0]] = telephonedir.Telephone(rec[0], telephoneTypes[rec[6]])

46telephoneDir.telephones.add(telephones[rec[0]])

47key = int(rec[1])