ATOOD - Project

Patternwizard

 

Developer-Guide

v0.2


Table of Contents

Table of Contents. 2

1      Introduction.. 3

2      Specification and Design.. 3

2.1       Specification.. 3

2.2       Design.. 4

2.2.1        GUI: 4

2.2.2        SW Design: 4

2.3       Functionality of the application.. 5

2.3.1        Main (root cluster) 5

2.3.2        States: 6

2.3.3        GUI 6

2.3.4        Code Generator. 6

2.3.5        Parser. 6

3      Clusters. 6

3.1       States. 6

3.2       GUI 9

3.3       Parser.. 10

3.3.1        Classes. 11

3.4       Variables. 11

3.4.1        Classes. 12

3.5       String Classes. 14

3.5.1        Classes. 14

3.6       Code Generator.. 15

4      Test Suite.. 16

5      Extendibility.. 18

5.1       Adding a new design-pattern.. 18

5.1.1        Code generator specific tasks. 18

5.1.2        States specific tasks. 18

5.1.3        GUI specific tasks. 18

6      Quality.. 19

7      Improvements: 19

 


1         Introduction

 

This guide describes the Pattern Wizard Tool from the developer viewpoint. The overall design, as well as the design of the single clusters are depicted, containing the description of the representative classes. Extendibility of the Pattern Wizard was one of the main goals in the design of the tool. Genericity and decentralization were also aimed at, as described in Chapter 2 of this document.

The single clusters are documented in Chapter 3. The functionality of the classes is shown in detail for representative classes of the clusters, in order to facilitate the extension of the tool to further patterns. Extendibility is discussed in Chapter 5.

Additionally, testing of the tool on sample classes is documented.

 

For the development and implementation the EiffelStudio development environment, with EiffelStudio 5.3 as the new compiler of the ISE Eiffel environment and the new graphical builder EiffelBuild, were used.

 

2         Specification and Design

 

2.1      Specification

 

The user is expected to be familiar with design patterns. For an overview of the tool’s functionality please also refer to the user guide.

 

The specification of the Pattern Wizard Tool covers the following:

-         Design and implementation of a design pattern wizard (GUI and “business model”) in Eiffel

-         5 design patterns (Abstract Factory, Factory Method, Builder, Prototype, Singleton)

-         Should be extendible to all design patterns described by Gamma et al.

-          Ability to select design pattern and classes to be generated

-          Once the user has pressed the button “Create” (whatever you call it), the wizard should generate the corresponding code and be closed;

-          If the user presses “Cancel”, the wizard should be closed without generating any code.

 

 

The Tool was not aimed to have software correction facilities and inconsistent input classes likely produce an exception during the execution of the Pattern Wizard Tool. Consistency checking is limited to feature name duplication. If features with the same name exist in the code, a warning appears in the result report of the tool and a comment is added in the correspondent class text.

 

2.2      Design

 

2.2.1      GUI:

 

The tool consists of one GUI window whose content is updated for each design pattern. Generally three kinds of views can be identified:

  1. Initial window: Shows the pattern choice drop down menu and the cluster-name entry field
  2. Design Pattern specific window: Top part is similar to initial window, bottom part contains the property fields, which can be changed by the user or contains specific default names
  3. Result window: The purpose of this window is to show the result report made by the code parser and generator.

 

2.2.2      SW Design:

 

The design of SW was done with respect to small interfaces between the different clusters.

 

Following graphic illustrates an overall view of the software architecture :

 

 

 

 

 

 

 

 

 

 

 


Figure 1 : Overall view of the SW-architecture

 

The application is started in the main part. Afterwards the remaining clusters take the lead of the application. 

First the initial window is drawn. The user interacts through the GUI with the STATES cluster (layer) and activates the next state in the transition list. As soon as a user activity (usually clicking the ‘create’ button) occurs the CODEGENERATOR is activated, which will occasionally use the PARSER to validate already existing classes or generate new source files

 

2.3      Functionality of the application

 

The pattern application proceeds in two steps. First strings containing the pattern specific code are produced. In case the pattern is applied to an existing class, both the code and the class are parsed, and merged clause by clause into one class.

 

The application is divided into five parts (also called clusters)

-         Main or root cluster

-         States

-         Gui

-         Code Generator

-         Parser

 

 

The data flow between these clusters and the file system and the result report (singleton instance) is shown in the following picture.

 

 

Figure 2: Data flow diagram

 

2.3.1      Main (root cluster)

The main part is responsible to start the application and to pop up the first window (initial window). After that, the actions on the user interface determine the process of the application and the agents behind them keep the whole application alive. Agents are "operation wrapper" objects that are mainly associated in this application with certain events of the user interface, such as a mouse click on a button.

 

2.3.2      States:

Implements the functionality of the windows and the transition between them.

It is implemented with the ‘state’ design pattern. Every window created by the application is the client of a state. The user interacts with the GUI and launches new states by pushing a button ‘do’, ‘cancel’, etc.

 

2.3.3      GUI

Cluster GUI contains the implementation of the graphical user interface windows; 

 

2.3.4      Code Generator

The builder cluster can be divided into 3 main parts:

-         The classes IMPLEMENTATION_DESCRIPTOR, CODE_ENGINE and CLASS_BINDING: the first is the interface between the GUI and the code generating classes and hands over the user input data. CODE_ENGINE implements the features to create the pattern-specific code, and starts the parser in the case that classes are present in the assigned cluster. CLASS_BINDING is a helper class to the Code_engine.

-         The subcluster VARIABLES: Contains the user input information, specific to the pattern.

-         The subcluster STRING_CLASSES: Predefined pattern code, deposited in Eiffel classes, with the functionality of variable-replacement and code repetition.

 

2.3.5      Parser

A parser for eiffel classes, with the capability to merge two classes with the same class name into one final class.

 

 

3         Clusters

3.1      States

As it is mentioned above, the state design pattern is used for this application. The code of the pattern resides in the cluster STATES. The State pattern is useful when you want to have an object represent the state of an application, and you want to change the state by changing that object. The benefit of the State pattern is that state-specific logic is localized in objects that represent that state.

This cluster contents most of functionality of the application. A state has a window and can react to user inputs as mouse clicks on buttons, dropdown menus etc.

 

Figure 2: State pattern used in the application

 

All existing states are stored in the array ‘states’ in the STATE_LIST. The state transformation (from one state to another one) depending on the user’s input is defined in the array ‘transition’. When the application is started, both arrays (states and transition) are initialized. The application starts with the state STATE_INTIAL (started with feature execute_first_session). There exists no central loop cycle which deals with all user activities and step further to the next state. But there are agents, which handles the user events and activates the next state by calling ‘execute_next_session’ from STATE_LIST.

(So feature ‘execute_next_session is a callback function)

 

The transition from one state to the other is defined in a matrix. Following table illustrates the transition:

 

Note: target and source are type of states


Table 1:  Transitions choice dependency

Target

choice = label

1

2

3

4

5

6

7

8

9

state source

 

 

 

 

 

 

 

 

 

 

1 initial

 

1

2

4

6

7

8

 

 

10

2 abstract factory I

 

1

2

4

6

7

8

3

1

10

3 abstract factory II

 

1

2

4

6

7

8

9

1

10

4 factory method I

 

1

2

4

6

7

8

5

1

10

5 factory method II

 

1

2

4

6

7

8

9

1

10

6 builder

 

1

2

4

6

7

8

9

1

10

7 prototyp

 

1

2

4

6

7

8

9

1

10

8 singleton

 

1

2

4

6

7

8

9

1

10

9 result

 

1

2

4

6

7

8

1

1

10

10 final

 

 

 

 

 

 

 

 

 

 

 

 

Table 2 :  User choices or labels

Label

Type of GUI component

number

Please Choose

1. list item in drop down menu

1

abstract factory

2. list item

2

factory method

3. list item

3

Builder

4. list item

4

prototyp

5. list item

5

singleton

6. list item

6

Create, Proceed

Button

7

Cancel, New

Button

8

Quit

Button

9

 

For example:

The User sees the first window of the state STATE_FACTORY_METHOD_INITIAL. This is the source state 4 (factory method I). The User clicks now the button ‘Proceed’ at the bottom of the window (Label Create, Proceed). This label activity has the number 7. So according the matrix list the next state is number 5 which is the state factory II .

 

 

 


Following graphic shows a regular window with all possible user choices (labels):

 

7                 8              9

 

1

2

3

4

5

6

 

 

 

 

 

 


Figure 3: User Choices

 

3.2      GUI

 

During the lifetime of the application there exists only one window reference. In order to change the content of this window the memory block to which the reference refers to has to be overwritten. The reference for this window is kept in a singleton called GUI_OBJECTS. Other user data that has to live over different states (like the cluster name) are also stored in this object.

Following picture shows the dependencies of the application with the GUI cluster.

 

Figure 4: class diagram of the Gui cluster

Each state has an own window type and because all windows need similar functionalities a deferred class WINDOW is introduced

 

At startup the state STATE_INITIAL is the state that defines the startup view of the application. The startup (or initial) view is created with the object of type WINDOW_INITIAL.

 

Following picture shows the dependencies between some state-classes and the according window-classes:

 

 

Figure 5: class diagram of the State cluster

 

3.3      Parser

The purpose of this cluster is to provide functionality to parse existing class files. It differentiates between clusters, classes and features. A cluster is mainly a list of classes and provides functionality like opening a cluster from a directory, save a cluster (i.e. all its class files). A class object is a representation of a class file. Class representation is divided into indexing, class name, inheritance, creation, list of feature objects and invariants. All of these are individually accessible and settable. Furthermore a class can be set expanded, separate or deferred. As a special feature, an instance of class_obj can be merged with another instance of class_obj. Thereby indexing, inheritance, creation and invariants are joined. Features are joined only if they have unique names, otherwise both features are added to the class. This requires the user to manually change one of the two names or merge them before compiling the generated code. An added comment to one of the features indicates the duplicated feature.

A feature object finally represents a single feature. It is divided into name, export status, clause (e.g. -- Access), arguments, return type, comment, preconditions, local variables, postconditions and do clause.  All of them can be set or read.  Furthermore a feature object can be set deferred or once.

The dependencies among the classes are shown in Figure 6. Please refer to the Appendix A for the listings of the functions of each class.

 

 

Figure 6: class diagram of cluster ‘parser’

 

3.3.1      Classes

CLASS_OBJ: inherits from class OBJ. It represents a class object. On creation a file or string that represent a class text is parsed and divided into its key parts.

 

SCAN: is a deferred class. Is ancestor of CLASS_SCAN and FEATURE_SCAN. This class inherits from SCANNING and ARGUMENTS, two classes from the lex library cluster. On creation of an instance of this class, my_Eiffel_lex is – if not already existing – created. Attributes indicate whether a file or a string should be parsed. A few features help to move to a desired position within the text.

 

 

 

3.4      Variables

 

The VARIABLES classes are pattern-specific and contain the default class-names for a pattern, which may be exchanged by the Gui application. This class serves as interface between the Gui and the code-generating classes. The purpose is to provide the default class-names to the Gui, and to provide the user input to the code-generating classes.

 

 

Figure 6: class diagram of cluster ‘variables’

 

3.4.1      Classes

 

VARIABLE_LIST: The name of the classes, which shall be extended with the same features of the pattern are stored in a list of strings. VARIABLE_LIST indeed inherits from the library class LINKED_LIST[G], with the actual generic parameter STRING. The functionality added to this class is to allow only class-name valid entries, and no repeated entries (case un-sensitive); empty strings are also not allowed. The query for checking for class-name validity is inherited from VALIDATION, used for the user input validation in the GUI. All strings are stored in uppercase. The list cannot be completely emptied.

The ADT of this class depicts its main functionalities. The implementation of the axioms, which are not inherited from the library class, is referenced in the source code by the axiom’s numeric identifier.

 

Table 3 : ADT of VARIABLE_LIST

Type:

VARIABLE_LIST  (queue, entries with only one occurrence are allowed )

Functions:

Creation

new                          -> VARIABLE_LIST

Commands

extend:                   VARIABLE_LIST  * STRING  |-> VARIABLE_LIST  

reset_to                   VARIABLE_LIST * STRING |-> VARIABLE_LIST

Queries

item :                        VARIABLE_LIST |-> STRING

count :                     VARIABLE_LIST -> INTEGER

empty :                     VARIABLE_LIST -> BOOLEAN

has :                         VARIABLE_LIST * STRING -> BOOLEAN

occurrence:             VARIABLE_LIST * STRING -> BOOLEAN

Preconditions:

item( vlist ) requires not empty( vlist )

put( vlist, s ) requires s /= void and is_valid_classname(s) and not has( s )

reset_to( vlist, s ) requires s /= void and is_valid_classname(s)

Axioms:

1) empty( new ) 

2) not empty( put( vlist, s ) )

3) not empty(reset_to( vlist, s ) )  and count( reset_to( vlist, s ) ) = 1

4) item( put(vlist, s)  ) = s if  empty(vlist) ,

                                    = item( vlist ) otherwise

5) remove( extend( vlist , s ) =  vlist if empty( vlist ), 

                                              = extend ( remove( vlist ), s  )  otherwise

6) reset_to( put( vlist, s ), s’ ) = reset_to( vlist, s’ )

7) occurrence( item( vlist ) ) = 1   

8) has( put( vlist, s), s )

 

 

VARIABLES: is a deferred class. The container for objects of type VARIABLE_LIST is a hash table with pattern-specific keys, implemented in the heirs of this class.

The variable lists of these classes are used in the string classes for the code generation and may therefore not be empty, in order to guarantee the correct text output of the string classes.

For the list of functionalities please refer the following ADT – description

 

Table 4 : ADT of VARIABLES

Type:

VARIABLES

Functions:

  Creation

new  :                       ->  VARIABLES

  Command

item :                        VARIABLES * KEY |-> VARIABLE_LIST

reset_to :                VARIABLES * STRING * KEY  |-> VARIABLES

replace :                  VARIABLES * VARIABLE_LIST * KEY  |-> VARIABLES

new_binding         VARIABLES * VARIABLE_LIST * STRING  ->  VARIABLES

  Query

empty :                    VARIABLES -> BOOLEAN

has :                         VARIABLES * KEY -> BOOLEAN

Preconditions:

new_binding(var,list, k) requires k /= void and not empty(k)

replace(var, vlist, k) requires has( var, k ) and vlist /= void and not empty(vlist)

item(var, k) requires has(var, k)

reset_to(var, s, k) requires has(var, k)

Axioms:

1)       not empty(new)   -- class inv

2)       item(put(var, vlist, k), k) = vlist

3)       reset_to(replace(var, vlist, k), s, k) = replace( var,  reset_to( vlist, s ), k ) 

5)       

 

In the descendants, the keys are created during instantiation of the object, and also default class-names are given for each key. The access to the hash table is allowed only to features of the class, whose name explicitly shows the kind of variable that is retrieved or is set by the call of the feature. The keys are unchangeable for most of the patterns implemented (FACTORY_METHOD_VARIABLES, PROTOTYPE_VARIABLES, SINGLETON_VARIABLES, BUILDER_VARIABLES). In the case of the Abstract Factory Pattern, discussed next, the keys had to be adapted to the user input. The class invariant for proper keys was implemented by the hidden feature ‘keys_set’, adusted to each pattern.

 

ABSTRACT_FACTORY_VARIABLES: these variables have the keys for the ‘Abstract Factory Pattern’ and may serve as an example for the implementation of ‘extendible’ keys: they may be extended during the lifetime of the object. Indeed the number of product classes is 2 after creation and may be changed afterwards. If the number of product classes is reduced during the object’s lifetime, keys, which are not needed, are simply not used in the code generation. Otherwise keys and their default content are dynamically added.

The class-hierarchies were reflected in the dynamic adaptation of the names of the concrete classes to the class names of the abstract classes, implemented in the setter methods of the class-names of the deferred classes. This was also reasonable from the viewpoint of the user interface (GUI), as entering of the names of the concrete class-names was possible only after the abstract class-names were set.

 

 

 

3.5      String Classes

 

The purpose of this cluster is to provide the pattern specific code to the parser. The code for the Patterns ‘Abstract Factory’, ‘Factory Method’, ‘Builder’, ‘Prototype’, ‘Singleton’  is made retrievable.

 

3.5.1      Classes

 

STRING_CLASS : is a deferred class. It contains the class text, needed by the code generating classes.

Each class of the pattern corresponds to an heir of string class. The code is deposited in strings, which contain the ‘pattern variables’ in entities. The variables are, as predictable, contained in instances of the class VARIABLE_LIST. They serve to adapt the content to the user input. Furthermore code repetition is implemented by the iteration over the list.

For the main functionalities please refer also to the ADT of this type

 

Table 5 : ADT of VARIABLE_LIST

Type:

STRING_CLASS

Functions:

  creation

new  :                      VARIABLES  |->  STRING CLASS

command

generate_all_strings : STRING CLASS -> STRING CLASS

text :                             STRING CLASS |-> STRING

all_generated:             STRING CLASS -> BOOLEAN

set_classname :          STRING CLASS * STRING |-> STRING_CLASS

classname :                  STRING CLASS |-> STRING

set_inheritance :        STRING CLASS * STRING |-> STRING_CLASS

inherit_from :            STRING CLASS |-> SET[ STRING ]

variables  :                   STRING CLASS -> VARIABLES

query

equal                            STRING CLASS * STRING CLASS -> BOOLEAN

 

Preconditions:

new( var ) requires var /= void  and not var.is_empty

text ( sc ) requires all_generated ( sc )

set_classname( sc, s ) requires s /= void and not empty(s)

 

 

3.6      Code Generator

 

This cluster has the control over the code generation.

First, IMPLEMENTATION_DESCRIPTOR hands over the user input information, which are: 

-         the kind of pattern to generate (‘pattern_no’),

-         the cluster where to save the resulting classes (‘cluster_name’) and

-         the pattern-specific class-names, contained in the ‘variables’ of the class.

The report of the code generating actions is saved in string ‘result-report’ in this class, and is written by the CODE_ENGINE and by the parser classes CLUSTER_OBJ and CLASS_OBJ. The IMPLEMENTATION_DESCRIPTOR was implemented as a singleton to be easily accessed from the GUI implementation and the parser classes.

 

CODE_ENGINE executes the generation of the code. The procedure ‘create pattern’ chooses the right feature to execute. First, the code implemented in the string-classes is processed, and the items of the ‘variables’ are replaced by the actual values. If classes exist in the target cluster, they are parsed and deposited in CLASS_OBJ and FEATURE_OBJ objects. In the case of identical class-names, the generated code is also parsed, and the contents of the two classes are merged, as described in the Parser section.

A helper class CLASS_BINDING facilitates the writing of the procedure for the code generation. Cloning of the objects of type STRING_CLASS ensures avoidance of erroneous overwriting of entities of the class. The procedure ‘create_subclass’ helps to correctly implement the class hierarchies in the pattern.

Figure 7: class diagram of cluster ‘code_generator’

 

 

 

4         Test Suite

The test suite is organized in the following way: In a directory called test_suite there exists a subfolder for each design pattern implemented. For each design pattern there again exist two subfolders: new_cluster (not included unfortunately in the zip file delivered) and existing_cluster. The subfolder new_cluster is empty. To test the ability of the tool to generate code from scratch use this folder as cluster name of the appropriate design pattern in the tool. Results are then stored in this folder. Check the results against your manually validated code.

To test the ability of the tool to work on existing code, use the example classes in the directory existing_cluster. These example classes will be edited. A copy of the original classes will automatically be stored. Make sure you delete the edited files and remove the .bak extension of the backup files before you test again.

 

For the Pattern the following classes are prepared

-         Abstract Factory :  a toy_factory.e and a military_factory.e may get concrete factories, and use the Pattern Wizard to implement the abstract factory and the product hierarchies.

-         Factory Method:  my_producer.e is can be used to produce an object of a type of your choice.

-         Builder :  the classes new_house.e shall be linked to windows.e and walls.e by the product – parts client relation of the Builder pattern, adding also the classes to implement the builder itself.

-         For Prototype a ferrari.e expects you to make e prototype out of it and for the Singleton Pattern feel free to use the my_car.e or keys.e classes. 

 

The results are shown in the appendix B of this guide.

 

5         Extendibility

5.1      Adding a new design-pattern

 

5.1.1      Code generator specific tasks

-         Implement a new class heir of VARIABLES, containing the features to obtain and set the class names of this pattern.

-         Extend the Pattern Constants by the default class-names, used to implement the initialization feature ‘init_bindings’ in the new Variables-class.

-         Implement a string class for each class of the pattern.

o       Copy the pattern-class text to the STRING_CLASS text, and assign the clauses to the features indexing_string, create_string, feature_string, etc. ( use the string delimiters  “[ and  ]”  for multiline strings ).

o       Implement a local entity of type VARIABLE_LIST for every exchangeable class name, which appears in the text of this class. Use these entitites for string replacement and code repetition.

o       Implement a ‘make_default’ creation procedure of the STRING_CLASS, where default values are set for the class-name, and the inherited class.

-         Implement the create-procedure in the CODE_ENGINE class, by creating objects for all type of string-classes in the pattern ( ‘make_default’). Instantiate an object of class CLASS_BINDING from a STRING_CLASS  by assigning the class name, and use the ‘create_subclass’ of procedure for implementing class-hierarchies

-         Extend the Application Constant

-         Extend the set_pattern feature of the IMPLEMENATION_DESCRIPTOR with the creation procedure for the new VARIABLES – class and the assignment of the pattern_no.

 

5.1.2      States specific tasks

 

-         Each state has an own window. So before another design pattern is added, it should be clear how many windows with pattern specific property fields are used.

-         Each of these state classes has to be inherited from STATE_PARENT.

-         Adapt feature ‘display’ to display the start values in the GUI

-         Adapt feature ‘do_action’ to your needs

 

5.1.3      GUI specific tasks

 

-         Add a new window class and inherit it from class WINDOW, which is the deferred class with general functionality for all used windows

-         Add setter and getter functions for all texts (usually used in input boxes) which could be changed by the user

 

 

The application can easily be adapted to any need of  Eiffel source refactoring.

 

6         Quality

 

We tested the application repeatedly and found no bugs. All sources could be generated or adapted properly.

 

 

 

7         Improvements:

-         The interaction between STATES and CODE_GENERATOR could be improved. At the moment a state object has the lead about parser and code_generator., especially it has to know everything about the exported features of the IMPLEMENTATION_DESCRIPTOR. More suitable would have been to use a generic array for parameter delivery. A solution could also have been to send directly the GUI-components to the CODE_GENERATOR cluster. Another improvement would be to combine all the GUI components which can be changed by the user and all variables types of the CODE_GENERATOR.

-         more decentralized code creation procedure

 
Appendix A

 

ADT Specifications (incomplete)

 

 

Type:

OBJ

Functions:

name: OBJ ® STRING

set_name: OBJ ´ STRING ® OBJ

merge: OBJ ´ OBJ ® OBJ

 

Type:

CLUSTER_OBJ

Functions:

name: CLUSTER_OBJ ® STRING

merge: CLUSTER_OBJ ´ CLUSTER_OBJ ® CLUSTER_OBJ

make_new: CLUSTER_OBJ

make_from_directory: STRING ® CLUSTER_OBJ

last_found: CLUSTER_OBJ ® CLASS_OBJ

has_class: CLUSTER_OBJ ´ STRING ® BOOLEAN

save: CLUSTER_OBJ ® CLUSTER_OBJ

save_as: CLUSTER_OBJ ® CLUSTER_OBJ

 

Type:

CLASS_OBJ

Functions:

make_new: CLASS_OBJ

make_from_file: STRING ® CLASS_OBJ

make_from_string: STRING ® CLASS_OBJ

text: CLASS_OBJ ® STRING

name: CLASS_OBJ ® STRING

name_clause: CLASS_OBJ ® STRING

inheritance_clause: CLASS_OBJ /® STRING

creation_clause: CLASS_OBJ /® STRING

feature_clause: CLASS_OBJ /® STRING

feature_by_name: CLASS_OBJ ´ STRING /® FEATURE_OBJ

invariant_clause: CLASS_OBJ /® STRING

last_found: CLASS_OBJ /® FEATURE_OBJ

has_feature: CLASS_OBJ ´ STRING ® BOOLEAN

has_exported_feature: CLASS_OBJ ´ STRING ® BOOLEAN

has_createion_feature: CLASS_OBJ ´ STRING ® BOOLEAN

is_deferred: CLASS_OBJ ® BOOLEAN

is_expanded: CLASS_OBJ ® BOOLEAN

is_separate: CLASS_OBJ ® BOOLEAN

add_indexing: CLASS_OBJ ´ STRING ® CLASS_OBJ

add_default_indexing: CLASS_OBJ ® CLASS_OBJ

add_inheritance: CLASS_OBJ ´ STRING ® CLASS_OBJ

add_creation: CLASS_OBJ ´ STRING ® CLASS_OBJ

add_creation_list: CLASS_OBJ ´ LIST[STRING] ® CLASS_OBJ

add_feature: CLASS_OBJ ´ FEATURE_OBJ ® CLASS_OBJ

add_feature_list: CLASS_OBJ ´ LIST[FEATURE_OBJ] ® CLASS_OBJ

add_invariant: CLASS_OBJ ´ FEATURE_OBJ ® CLASS_OBJ

set_deferred: CLASS_OBJ ® CLASS_OBJ

set_expanded: CLASS_OBJ ® CLASS_OBJ

set_separate: CLASS_OBJ ® CLASS_OBJ

save: CLASS_OBJ ® CLASS_OBJ

merge: CLASS_OBJ ´ CLASS_OBJ ® CLASS_OBJ

sort_features_by_type: CLASS_OBJ ® CLASS_OBJ

Axioms:

NOT is_deferred AND is_expanded

NOT is_deferred AND is_separate

NOT is_expanded AND is_separate

 

 

Type:

FEATURE_OBJ

Functions:

make: FEATURE _OBJ

text: FEATURE _OBJ ® STRING

name: FEATURE _OBJ ® STRING

export_status:          FEATURE_OBJ ® STRING

feature_clause: FEATURE _OBJ ® STRING

argument: FEATURE _OBJ /® STRING

return_type: FEATURE _OBJ /® STRING

comment: FEATURE _OBJ /® STRING

require_clause: FEATURE _OBJ /® STRING

local_clause: FEATURE _OBJ /® STRING

do_clause: FEATURE _OBJ /® STRING

ensure_clause: FEATURE _OBJ /® STRING

is_deferred: FEATURE _OBJ ® BOOLEAN

is_once: FEATURE _OBJ ® BOOLEAN

add_export_status: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

add_export_status_list: FEATURE _OBJ ´ LIST[STRING] ® FEATURE _OBJ

set_feature_clause: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

add_argument: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

set_return_type: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

add_require: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

add_local: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

add_comment: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

add_do: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

add_ensure: FEATURE _OBJ ´ STRING ® FEATURE _OBJ

set_once: FEATURE _OBJ  ® FEATURE _OBJ

set_deferred: FEATURE _OBJ ® FEATURE _OBJ

merge: FEATURE _OBJ ´ FEATURE _OBJ ® FEATURE _OBJ

 

Type:

SCAN

Functions:

make: SCAN

from_file: SCAN ® BOOLEAN

from_string: SCAN ® BOOLEAN

set_from_file: SCAN ® SCAN

set_from_string: SCAN ® SCAN

goto_keyword: SCAN ´ INTEGER ® SCAN

goto_next_keyword: SCAN ® SCAN

goto_next_token_of_type: SCAN ´ ARRAY[INTEGER] ® SCAN

goto_next_token_not_of_type: SCAN ´ ARRAY[INTEGER] ® SCAN

 

 

 

 

 

Appendix B

 

Test Result

 

Here the results of the application of the Builder Pattern to the prepared classes new_house.e, walls.e and windows.e, as described in the Test Suite Section, are shown:

 

Builder Pattern

 

Original classes

indexing

        

 

       description: "[

                     My new house 

                     ]"

 

 

class

 

       NEW_HOUSE

 

create

 

       make

 

feature  -- Initialization

      

       make is      

              do

                     is_new := true

              ensure

                     is_new_house: is_new

              end

 

feature  -- Access

      

       walls : WALLS

 

feature  -- Access

      

       windows : WINDOWS

 

feature  -- Status report

 

       is_new :BOOLEAN

 

invariant

      

       is_a_new_house : is_new

 

 

end -- class NEW_HOUSE

 

 

-----------------------------------------------------------------------------------------

 

indexing

 

       description: "[

                     Windows of a new house.

                     ]"

 

class WINDOWS

 

 

feature -- Measurement

 

       cost : INTEGER is

                     --  cost of the windows

              do    

                     Result := number * 10

                     if bright then

                           Result := Result * 2

                     end

              end          

 

 

feature -- Status report

 

       bright : BOOLEAN

 

       number : INTEGER

 

feature -- Status setting

 

       set_bright is

                     -- are the windows bright

              do

                     bright := true

              ensure

                     bright : bright

              end

 

       set_number ( n : INTEGER ) is

                     -- how many windows

              do

                     number := n

              ensure

                     number_set : number = n

              end

 

end

 

 

-----------------------------------------------------------------------------------------

 

indexing

 

       description: "[

                     Walls of a new house.

                     ]"

 

class WALLS

 

 

feature -- Measurement

      

       cost : INTEGER is

              -- the cost of these walls       

              do

                     Result := height * thickness

              end

 

feature -- Status report

 

       height : INTEGER

 

       thickness : INTEGER

 

feature -- Status setting

 

       set_height ( h : INTEGER ) is

                     -- how high shall the walls be

              do

                     height := h

              ensure

                     height_set : height = h

              end

 

       set_thickness ( t : INTEGER ) is

                     -- how thick shall the walls be

              do

                     thickness := t

              ensure

                     thickness_set : thickness = t

              end

 

end

 

 

Result report

+++++      REPORT OF THE PATTERN CREATION PROCESS      +++++

 

Starting the creation of the Builder Pattern code.

 

Creating class WINDOWS ...   done.

Creating class WALLS ...   done.

Creating class NEW_HOUSE ...   done.

Creating class HOUSE_BUILDER ...   done.

Creating class MY_HOUSE_BUILDER ...    done.

Creating class CLIENT ...   done.

Parsing object: T:\fabrizipgeordnet\eiffel\test_suite\builder\existing_cluster\WINDOWS.e...done.

Parsing object: T:\fabrizipgeordnet\eiffel\test_suite\builder\existing_cluster\WALLS.e...done.

Parsing object: T:\fabrizipgeordnet\eiffel\test_suite\builder\existing_cluster\NEW_HOUSE.e...done.

Backing up 'WINDOWS' ...    done.

Merging 'WINDOWS' and 'WINDOWS'   ...    done.

Saving and closing T:\fabrizipgeordnet\eiffel\test_suite\builder\existing_cluster\WINDOWS.e     ...       done.

Backing up 'WALLS'   ...    done.

Merging 'WALLS' and 'WALLS' ...    done.

Saving and closing T:\fabrizipgeordnet\eiffel\test_suite\builder\existing_cluster\WALLS.e       ...       done.

Backing up 'NEW_HOUSE'     ...    done.

Merging 'NEW_HOUSE' and 'NEW_HOUSE'      ...    WARNING: Feature 'windows' is duplicated. Manual merge required

WARNING: Feature 'walls' is duplicated. Manual merge required

done.

Saving and closing T:\fabrizipgeordnet\eiffel\test_suite\builder\existing_cluster\NEW_HOUSE.e   ...       done.

 

Task fulfilled !

Press 'New' to start again or 'Quit' to leave.

 

 

Resulting classes

indexing

 

       description: "[

                     Notify the builder when a new product should be built. 

                     ]"

       note: "Implementation of the Builder design pattern "

 

 

class CLIENT

 

create 

       make

 

 

feature {NONE} -- Initialization

 

       make (a_builder: like my_house_builder ) is

                     -- Set 'my_house_builder to 'a_builder'.

              require

                     builder_not_void : a_builder /= Void

              do

                     my_house_builder := a_builder

              ensure

                     my_house_builder_set: my_house_builder = a_builder

       end

 

feature -- Access

 

       my_house_builder : HOUSE_BUILDER

                     -- Product builder

 

feature -- Basic Operations

 

       build is

                     -- Call 'my_house_builder' to construct a new new_house

              do

                     my_house_builder.build

              ensure

                     new_house_not_void : my_house_builder.last_new_house /= Void

                     windows_not_void : my_house_builder.last_new_house.windows /= Void

                     walls_not_void : my_house_builder.last_new_house.walls /= Void

              end

 

 

 

invariant

 

       my_house_builder_not_void : my_house_builder /= Void

end

 

 

 

-----------------------------------------------------------------------------------------

 

 

indexing

 

       description: "[

                     Build product part by part. 

                     ]"

       note: "Implementation of the Builder design pattern "

 

 

deferred class HOUSE_BUILDER

 

feature -- Access

 

       last_new_house: NEW_HOUSE is

                     -- new_house under construction

              deferred

              end 

 

feature -- Basic operations

 

       build is

                     -- Create and build `last_new_house'.

       do

              build_new_house

              build_windows

              build_walls

       ensure

              last_new_house_not_void : last_new_house /= Void

              windows_not_void : last_new_house.windows /= Void

              walls_not_void : last_new_house.walls /= Void

 

 

end

 

 

 

-----------------------------------------------------------------------------------------

 

 

indexing

 

       description: "[

                     Build product part by part. 

                     ]"

       note: "Implementation of the Builder design pattern "

 

 

class MY_HOUSE_BUILDER

 

inherit

        HOUSE_BUILDER

 

feature -- Access

 

       last_new_house: NEW_HOUSE

                     -- new_house under construction

 

 feature {NONE} -- Implementation

 

       build_new_house is

                     -- Create and build `last_new_house'.

              do

                     debug

                           io.put_string (" Create new new_house.%N")

                     end

                     create last_new_house

              end

 

 

       build_windows is

                     -- Build part 1 of the product.

              do

                     last_new_house.set_windows ( create {WINDOWS})

                     debug

                           io.put_string (" Set new_house part 1.%N")

                     end

              end

 

 

       build_walls is

                     -- Build part 2 of the product.

              do

                     last_new_house.set_walls ( create {WALLS})

                     debug

                           io.put_string (" Set new_house part 2.%N")

                     end

              end

 

end

 

 

-----------------------------------------------------------------------------------------

 

 

indexing

      

        

 

       description: "[

                     My new house 

                     ]"

 

 

 

 

 

       description: "[

                     Product to be created by the concrete builder 

                     ]"

       note: "Implementation of the Builder design pattern "

 

 

 

 

class

       NEW_HOUSE

 

create

       make

feature   -- Initialization

      

      

       make is

                          

             

       do

 

                     is_new := true

             

       ensure

 

                     is_new_house: is_new

             

       end

 

 

feature   -- Access

      

      

       walls :WALLS

 

 

 

feature   -- Access

      

      

       windows :WINDOWS

 

 

 

feature  -- Access

 

      

       windows :WINDOWS                  --     WARNING: duplicated feature! Remove one version or merge the two features manually

 

 

 

 

feature  -- Access

 

      

       walls :WALLS               --     WARNING: duplicated feature! Remove one version or merge the two features manually

 

 

 

 

feature   -- Status report

 

      

       is_new :BOOLEAN

 

 

 

feature {HOUSE_BUILDER}  -- Status setting

 

      

       set_windows( part_1: like windows) is

                    

                     -- set 'windows' to 'part_1'.

             

       require

 

                     part_1_not_void: part_1 /= Void

             

       do

 

                     windows:= part_1

             

       ensure

 

                     windows_set: windows = part_1

             

       end

 

 

feature {HOUSE_BUILDER}  -- Status setting

 

      

       set_walls( part_2: like walls) is

                    

                     -- set 'walls' to 'part_2'.

             

       require

 

                     part_2_not_void: part_2 /= Void

             

       do

 

                     walls:= part_2

             

       ensure

 

                     walls_set: walls = part_2

             

       end

 

 

 

invariant

      

      

       is_a_new_house : is_new

 

 

 

 

end -- class NEW_HOUSE

 

 

-----------------------------------------------------------------------------------------

 

 

indexing

        

 

       description: "[

                     Walls of a new house.

                     ]"

 

 

        

 

       description: "[

                     Part of product to be created

                     by the concrete builder 

                     ]"

       note: "Implementation of the Builder design pattern "

 

 

 

 

class

       WALLS

 

feature  -- Measurement

      

      

       cost :INTEGER is

                      

              -- the cost of these walls       

             

       do

 

                     Result := height * thickness

             

       end

 

 

feature  -- Status report

 

      

       height :INTEGER

 

 

 

feature  -- Status report

 

      

       thickness :INTEGER

 

 

 

feature  -- Status setting

 

      

       set_height( h : INTEGER ) is

                    

                     -- how high shall the walls be

             

       do

 

                     height := h

             

       ensure

 

                     height_set : height = h

             

       end

 

 

feature  -- Status setting

 

      

       set_thickness( t : INTEGER ) is

                    

                     -- how thick shall the walls be

             

       do

 

                     thickness := t

             

       ensure

 

                     thickness_set : thickness = t

             

       end

 

 

 

 

end -- class WALLS

 

 

-----------------------------------------------------------------------------------------

 

indexing

        

 

       description: "[

                     Windows of a new house.

                     ]"

 

 

        

 

       description: "[

                     Part of product to be created

                     by the concrete builder 

                     ]"

       note: "Implementation of the Builder design pattern "

 

 

 

 

class

       WINDOWS

 

feature  -- Measurement

 

      

       cost :INTEGER is

                    

                     --  cost of the windows

             

       do

      

                     Result := number * 10

                     if bright then

                           Result := Result * 2

                     end

             

       end

 

 

feature  -- Status report

 

      

       bright :BOOLEAN

 

 

 

feature  -- Status report

 

      

       number :INTEGER

 

 

 

feature  -- Status setting

 

      

       set_bright is

                    

                     -- are the windows bright

             

       do

 

                     bright := true

             

       ensure

 

                     bright : bright

             

       end

 

 

feature  -- Status setting

 

      

       set_number( n : INTEGER ) is

                    

                     -- how many windows

             

       do

 

                     number := n

             

       ensure

 

                     number_set : number = n

             

       end

 

 

 

 

end -- class WINDOWS