4 UMA LINGUAGEM OO COM SUPORTE A ASSOCIAÇÕES O presente capítulo apresenta a extensão de uma linguagem de
4.2 EXEMPLO DE USO
4.2.1 Implementação do Modelo
O modelo foi implementado a partir do diagrama de classes ilustrado pela Figura 98, aplicando-se diretamente no código Association#, os padrões GRASP especialista, criador, controlador, baixo acoplamento e não fale com estranhos. Este último foi aplicado
na maior parte do projeto, excetuando-se pelas associações em que o association end utilizado para navegação é pertencente à associação.
O resultado desta implementação foi a camada de domínio para o sistema de universidade exemplificado, em que a aplicação tem acesso somente ao controlador fachada24, ilustrado pela Figura 100 e codificado parcialmente na Figura 101.
Figura 100. Controlador da camada de domínio e suas associações.
24 Larman, 2000.
Código Association# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
public class University {
public static readonly University INSTANCE =
new University(); private University() { }
// Association ends
private rolename Faculties [*] in UniversityToFaculty; private rolename Courses [*] in UniversityToCourse; private rolename Students [*] in UniversityToStudent; private rolename SelectedFaculty [0..1] in
UniversityToSelectedFaculty;
private rolename SelectedSubstitute [0..1] in
UniversityToSelectedSubstitute;
private rolename SelectedCourse [0..1] in
UniversityToSelectedCourse;
private rolename SelectedLecturers [*] in
UniversityToSelectedLecturers;
private rolename SelectedStudent [0..1] in
UniversityToSelectedStudent;
private rolename SelectedLanguage [0..1] in
UniversityToSelectedLanguage;
private rolename Languages [*] in UniversityToLanguage;
// Cadastro de Professores
public void RegisterFaculty(string name, int number)
{...}
public bool SelectFaculty(int number) {...} public void EditSelectedFaculty(string newName,
int newNumber){...}
public void DeleteSelectedFaculty() {...} public string GetSelectedFacultyName() {...} public int GetSelectedFacultyNumber() {...}
public IEnumerable<int> GetFacultiesNumbers() {...}
// Vínculo de Professores com seus Substitutos
public void SelectSubstitute(int substituteNumber) {...} public string GetSelectedSubstituteName() {...}
public int GetSelectedSubstituteNumber() {...}
public void AddSelectedSubstituteToSelectedFaculty()
{...}
public void emoveSelectedSubstituteFromSelectedFaculty()
{...}
public IEnumerable<int>
GetSubstitutesNumbersFromSelectedFaculty() {...} ...
}
Figura 101. Resumo do código Association # da classe controladora University. Para manter o padrão C#/Association# de nomes de métodos, atributos e association ends, estes iniciam sempre com a primeira letra maiúscula, na escrita de código.
A Figura 102 apresenta o código simplificado da classe Faculty. Nesta, assim como nas demais classes, não há a necessidade de encapsulamento dos atributos e criação de métodos setAtributo e getAtributo, porque são utilizados properties em vez de fields para a representação de atributos. Se houver necessidade futura de adicionar controles e/ou operações sobre a atribuição e a recuperação de valores, basta apenas definir um corpo para as operações set e get das properties, da mesma forma que em C#.
Código Association# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
public class Faculty {
// atributos
public string Name { set; get; }
public int Number { set; get; }
// association ends
private rolename Substitutes [*] in Substitutes; private rolename Substituted [*] in Substitutes; private rolename Lectures [*] in Teaches;
// operações
public Faculty(string name, int number) {...} public bool HasSubstitutes() {...}
public IEnumerable<int> GetSubstitutesNumbers() {...} public void RemoveAllSubstitutes() {...}
public void AddSelectedSubstitute(Faculty substitute)
{...}
public void RemoveSubstitute(Faculty substitute) {...} public void RemoveAllSubstituted() {...}
}
Figura 102. Resumo do código Association# da classe Faculty.
Observa-se que não há na classe Faculty, nenhuma referência à associação WorksFor. Isto porque, o association end de nome ras pertence à associação e não a classe. Houve a necessidade de uma pequena modificação do código desta classe em relação ao modelo: o association end de nome Substitutes teve sua multiplicidade alterada de 1..* para * porque é esperado que durante a execução do sistema, primeiro cadastrem-se os professores para que depois se determine quem será substituto de quem. Porém, a regra de negócio que todo professor deve ter pelo menos um substituto é mantida através da verificação da existência de substitutos (chamada do método HasSubstitutes) ao tentar vincular um professor a um curso. Se o professor não tem substitutos, não é possível suceder tal vínculo.
A Figura 103 apresenta o código simplificado das classes Course (linhas 1 a 18) e Student (linhas 20 a 39). Similar à classe Faculty em
relação à associação WorksFor, a classe Course não possui referências à associação CourseToAC e a classe Student não possui referências às associações StudentToRA e StudentToTA.
Código Association# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
public class Course {
// Atributos
public string Title { set; get; }
// Association ends
private rolename Learners [*] in Attends; private rolename Lecturers [1..*] in Teaches;
// Operações
public Course(string title,
IEnumerable<Faculty> lecturers) {...}
public void RemoveAllLecturers() {...}
public void AddLecturer(Faculty lecturer) {...} public void RemoveLecturer(int lecturerNumber) {...} public IEnumerable<int> GetLecturersNumbers() {...} public void AddLearner(Student learner) {...} public void RemoveLearner(int studentNumber) {...} public IEnumerable<int> GetLearnersNumbers() {...} } public class Student {
// atributos
public string Name { set; get; } public int Number { set; get; } public int Year { set; get; }
// association ends
private rolename Lectures [1..*] in Attends;
public Student(string name, int number, int year) {...}
// operações
public void AddLecture(Course course){...} public void RemoveLecture(Course course) {...}
public void SetMarkOnLecture(Course course, int mark)
{...}
public int GetMarkOnLecture(Course course) {...} public IEnumerable<string> GetCoursesTitles() {...} public void RemoveAllLectures() {...}
public bool IsAttendingCourse() {...} }
Figura 103. Resumo do código Association# das classes Course e Student. Por meio do uso do padrão controlador, a aplicação só modifica e acessa informações da camada de domínio pela chamada de métodos da única instância (singleton) da classe controladora University.
Empregando o padrão não fale com estranhos, as operações da classe controladora encadeiam chamadas a métodos de instâncias das classes associadas a ela. Estas, por sua vez, executam a operação em seu próprio escopo e/ou delegam essa chamada a instâncias de outras classes associadas a estas, assim sucessivamente. Por exemplo: o cadastro de um professor – que deve resultar na criação de uma instância de Faculty e na posterior associação desta com o singleton University, pela associação UniversityToFaculty – é feito pela chamada do método University.RegisterFaculty (linha 24 da Figura 101). Este é responsável por criar a nova instância e associar ela ao singleton.
Um exemplo mais complexo, em que a operação é delegada para além da instância da classe controladora, é: a vinculação de professores substitutos. Está é feita pela prévia seleção do professor a ser substituído (método University.SelectFaculty, linha 25 da Figura 101) e do professor a ser o substituto (método University.SelectSubstitute, linha 33 da Figura 101), seguido da chamada do método University. AddSelectedSubstituteToSelectedFaculty (linha 36 da Figura 101). Este último método, chama o método Faculty.AddSelectedSubstitute (linha 16 da Figura 102) da instância selecionada como professor a ser substituído, passando como argumento o professor selecionado como substituto. Então, neste método, a instância do professor a ser substituído adiciona em sua lista de substitutos, a instância do professor recebida como argumento, por meio da chamada do association end de nome Substitutes (linha 7 da Figura 102).
O código implementado em Association# para esta camada de domínio, assim como o código C# gerado a partir deste por tradução manual, e o código do teste de unidade deste, estão contidos integralmente no Apêndice C.