• Ingen resultater fundet

Design Patterns

In document Translation of a Subset of RSL into Java (Sider 108-112)

3.1 Design Options

3.1.2 Design Patterns

Figure 3.14 Left: Translator implemented in the source language. Right:

Translator implemented in the target language.

Low

RSL Java

Java

Low

RSL Java

RSL

Low

Figure 3.15The modified translator producing high quality target language.

High

RSL Java

RSL

Figure 3.16 Translation of the new version of the translator using the first version.

RSL Java

Java High

RSL Java

RSL

RSL Java

Java

Low High

Low

Low

The result of the translation of the second version of the translator is a translator producing high quality target language. However, the executable version of the translator is still implemented in the low quality target lan-guage. This is fixed by translating the second version of the translator using the executable version of itself, as shown in Figure 3.17.

The result of this is a translator producing high quality target language implemented in high quality target language.

Figure 3.17 Translation of the second version of the translation using the second version.

RSL Java

Java High

RSL Java

RSL

RSL Java

Java High

H igh

Low

High

you can use the solution over and over again” [7, p. 2] In software design, this concept applies to several levels of abstraction.

At a low abstraction level, there is often a need for structures to represent data in some way. An example of this is the need to represent data as a list or as a tree. The structures are independent of the actual content of the structure. A list of integers is not very different from a list of real numbers.

Therefore general solutions for representing different kinds of lists have been developed as well as methods for operating on these lists. Representation of different kinds of data structures and methods for operating on these structures have been described in numerous places [4].

At a higher level of abstraction, there may be a need for a solution for generating different output from the same input, or to ensure that only one instance of an object exists in an object–oriented language. Solutions for these kinds of design issues have also been described by several authors [7].

In the programming language chosen for this project, namely Java, there are libraries for many kinds of data structures as well as support for operating on them, i.e. solutions of the design issues of the first level of abstraction mentioned. No solutions are implemented for the higher level design issues.

Therefore, solutions of these kind of issues must be implemented by hand.

The following section deals with the visitor design pattern which will be used in the design of the translator.

Visitor Design Pattern

The purpose of the visitor design pattern is to separate a hierarchical struc-ture of objects from tasks which must be performed on the strucstruc-ture [7].

The standard way to implement a feature in a structure is to add a method for the feature to each object in the structure. Each method carries out the feature for the object and invokes the same method in the subparts in the structure. As an example, a feature for printing a structure is implemented

by adding a print method to each object in the structure. Another feature of the structure is then implemented as another method in each of the objects.

There are three problems with this solution:

1. Each feature is spread as methods in all the objects of a structure. This makes it difficult to get an overview of the feature.

2. Addition or removal of a feature requires changes in all objects of a structure. This makes changes in the functionality of a structure te-dious.

3. The object hierarchy often represents a hierarchical structure in the real world. The structure has nothing to do with the tasks that must be performed on the hierarchy. It makes the design less clear that the tasks and the structure are mixed together.

The visitor design pattern solves this by moving the methods of the different features into separate task objects. The task objects are called visitors. A visitor traverses a structure of objects and completes the task by performing a part of the task while it visits an object. The visitor design pattern works by adding one method to all the classes in the object structure. The method is typically namedacceptor visit and takes a visitor as argument. The method calls a unique method, named visitObject, where Object is the name of the structure, in the visitor with itself as parameter. It is the unique method in the visitor which performes a part of the task.

One example of such an object structure could be a representation of a questionnaire in a system for doing interviews using a computer. A question-naire consists of an introduction text and a number of questions. A question consists of a question text and a number of answer options. An answer op-tion consists of a text describing the answer opop-tion. This can be represented by three types of objects: a questionnaire object, a question object, and an answer option object. A questionnaire must both be validated and printed, therefore each object contains a method for doing so. The questionnaire structure is shown in Figure 3.18.

In Figure 3.19, the same object hierarchy for an interviewing system is shown implemented using the visitor design pattern. The print and validate

methods have been removed from the object structure. A class implementing the visitor interface has been added for each of the features.

Should the need arise for a new feature, it can be implemented as a third visitor in the second solution, whereas it would require addition of a method in each of the classes in the first solution.

The traversal of an object structure implementing the visitor design pat-tern can be placed in two places: either the traversal can be placed in the

Figure 3.18 Questionnaire–structure without the visitor design pattern.

+print() +validate() Questionnaire

+print() +validate()

Question

-questionnaire 1

-questions

*

-question 1

-answeroptions

*

+print() +validate() Answer Option

Figure 3.19 Questionnaire–structure with the visitor design pattern.

+accept() -text : String Questionnaire

+accept() -text : String

Question

+accept() -text : String Answer Option

-questionnaire 1

-questions

*

-question 1

-answeroptions

* +visitQuestionnaire()

+visitQuestion() +visitAnswerOption()

PrintVisitor

+visitQuestionnaire() +visitQuestion() +visitAnswerOption()

ValidateVisitor +visitQuestionnaire()

+visitQuestion() +visitAnswerOption()

Visitor

object structure in theacceptmethod, or it can be placed in the visitors. The most simple solution is to keep the traversal in the object structure, because then it is kept in one place and not in all the different visitors. The reason for putting the traversal in the visitors anyway is in case that the traversal are different for the different visitors, or if it is necessary to perform actions, both before and after the traversal of the subcomponents in the visitObject

methods.

A simple example of the need to perform actions both before and after the traversal of the subcomponents, is in case of a feature for printing a representation of a block in Java. If the traversal is put into the accept

method of the block as shown in Example 3.1, then the call to visitBlockmust be done either before or after the for–loop running through the statements.

The problem with this is that if the call to visitBlock is done before the for–loop then there is no place to put the corresponding System.out.println(”

}”); statement and vice versa. The solution is to place the traversal in the visitor, i.e. the traversal of subcomponents is placed in thevisitObject method for each object. This allows the visitor to perform actions both before and after the traversal of the subcomponents. In Example 3.2, the same example of printing a block in Java is shown with the traversal placed in the visitor.

Example 3.1 Visitor pattern – traversal in object structure.

public S t r i n g V i s i t o r implements V i s i t o r { public v i s i t B l o c k ( Block b l o c k ) {

System . out . p r i n t ( ”{” ) ; }

}

public c l a s s Block implements Element { A r r a y L i s t<Statement> s t a t e m e n t L i s t ; public void a c c e p t ( V i s i t o r v i s i t o r ) {

v i s i t o r . v i s i t B l o c k (t h i s) ;

f o r( Statement s t a t e m e n t : s t a t e m e n t L i s t ) s t a t e m e n t . a c c e p t ( v i s i t o r ) ;

} }

In document Translation of a Subset of RSL into Java (Sider 108-112)