MAY Best Practices » Historique » Version 19
Anonyme, 13/10/2014 18:01
| 1 | 18 | Anonyme | h1. MAY Best Practices |
|---|---|---|---|
| 2 | 1 | Anonyme | |
| 3 | 14 | Anonyme | {{>toc}} |
| 4 | |||
| 5 | 2 | Anonyme | h2. Typical Workflow |
| 6 | 1 | Anonyme | |
| 7 | 16 | Anonyme | In the Java project, sources (Java and SpeADL) edited by the developer are in the *src* folder (or equivalent), and the generated Java code is in the *speadl-gen* folder. |
| 8 | The *speadl-gen* folder is not meant to be touched by hand. |
||
| 9 | 1 | Anonyme | |
| 10 | 2 | Anonyme | Each modification of a SpeADL file is followed by the generation of its equivalent Java class. |
| 11 | |||
| 12 | A typical workflow for creating a component is as follow: |
||
| 13 | 13 | Anonyme | * [[SpeADL MAY Project SetUp|Creation of a SpeADL file]]. |
| 14 | * [[SpeADL Reference|Description of a component]]. |
||
| 15 | * Description of the interfaces needed by the component description. |
||
| 16 | * [[SpeADL Reference|Implementation of the component]] extending the corresponding class. |
||
| 17 | 2 | Anonyme | * And so on... |
| 18 | |||
| 19 | 17 | Anonyme | See [[SpeADL Minus Tutorial]] for a detailed tutorial. |
| 20 | |||
| 21 | 8 | Anonyme | h2. Module View |
| 22 | 9 | Anonyme | |
| 23 | 2 | Anonyme | On top of component declarations, interfaces and component implementation, it is relevant to define sometimes datatypes used in the interface or as type parameters of the components used. |
| 24 | |||
| 25 | A software component, its declaration, its implementation and classes it relies on form altogether what is called a module. |
||
| 26 | |||
| 27 | When creating interfaces or datatypes for one or several components, it is important to ask oneself to which module (i.e., with a given component) these declarations should belong to and why. |
||
| 28 | |||
| 29 | h2. Project Organisation |
||
| 30 | |||
| 31 | 15 | Anonyme | For a simple project, a good organisation of the src directory is as follow: |
| 32 | 2 | Anonyme | * Package my.project |
| 33 | ** SpeADL file *myproject.speadl* with a single namespace *my.project*. |
||
| 34 | ** Package *interfaces* containing the interfaces declarations |
||
| 35 | ** Package *impl* containing the implementations |
||
| 36 | 10 | Anonyme | ** Package *datatypes* containing extra classes needed |
| 37 | 2 | Anonyme | ** Package *exception* containing exceptions needed in the interfaces |
| 38 | |||
| 39 | In this case, all the modules are intermixed together. |
||
| 40 | |||
| 41 | For a more complex project, a good organisation of the src directory is as follow: |
||
| 42 | * Package my.project |
||
| 43 | ** Package aComponent |
||
| 44 | *** SpeADL file *aComponent.speadl* |
||
| 45 | 10 | Anonyme | *** Package *interfaces* containing the interfaces declarations owned by this component |
| 46 | *** Package *impl* containing the implementation of the component |
||
| 47 | *** Package *datatypes* containing extra classes needed by this component |
||
| 48 | *** Package *exception* containing exceptions needed in the interfaces owned by this component |
||
| 49 | 2 | Anonyme | ** Package anotherComponent |
| 50 | *** ... |
||
| 51 | |||
| 52 | In this case each module has its own package. |
||
| 53 | |||
| 54 | h2. Exploiting the Eclipse Editor |
||
| 55 | |||
| 56 | h3. Errors |
||
| 57 | |||
| 58 | When creating a Java file to implement a component, one has to extend the Java class generated from the component declaration. |
||
| 59 | |||
| 60 | 4 | Anonyme | Errors are shown in the Java editor, and the Quick Fix *Add unimplemented methods* proposed by Eclipse will generate automatically the skeleton for the Java file. |
| 61 | 2 | Anonyme | |
| 62 | From that: |
||
| 63 | <pre> |
||
| 64 | public class MySimpleComponentImpl extends MySimpleComponent { |
||
| 65 | } |
||
| 66 | </pre> |
||
| 67 | |||
| 68 | We get that: |
||
| 69 | <pre> |
||
| 70 | public class MySimpleComponentImpl extends MySimpleComponent { |
||
| 71 | @Override |
||
| 72 | protected AnotherJavaInterface make_p1() { |
||
| 73 | // TODO Auto-generated method stub |
||
| 74 | return null; |
||
| 75 | } |
||
| 76 | } |
||
| 77 | </pre> |
||
| 78 | |||
| 79 | This gives the possibility to very quickly approach the implementation of a component. |
||
| 80 | |||
| 81 | h3. Completion |
||
| 82 | |||
| 83 | When implementing the *make_XXX()* method of a provided port, one can exploit completion to gain a lot of time. |
||
| 84 | For example in the following situation (just after using the Quick Fix): |
||
| 85 | <pre> |
||
| 86 | class MySimpleComponentImpl extends MySimpleComponent { |
||
| 87 | @Override |
||
| 88 | protected AnotherJavaInterface make_p1() { |
||
| 89 | // TODO Auto-generated method stub |
||
| 90 | return null; |
||
| 91 | } |
||
| 92 | } |
||
| 93 | </pre> |
||
| 94 | |||
| 95 | 7 | Anonyme | Remove the _null_ after the return statement and replace it with _new AnotherJavaInterface_, use completion (*Ctrl+Space*) and select *AnotherJavaInterface() Anonymous Inner Type* to generate the anonymous type declaration as well as the skeleton to implement its methods: |
| 96 | |||
| 97 | <pre> |
||
| 98 | public class MySimpleComponentImpl extends MySimpleComponent { |
||
| 99 | @Override |
||
| 100 | protected AnotherJavaInterface make_p1() { |
||
| 101 | return new AnotherJavaInterface() { |
||
| 102 | @Override |
||
| 103 | public Integer test() { |
||
| 104 | // TODO Auto-generated method stub |
||
| 105 | return null; |
||
| 106 | } |
||
| 107 | }; |
||
| 108 | } |
||
| 109 | } |
||
| 110 | </pre> |
||
| 111 | 19 | Anonyme | |
| 112 | h2. Implementing Provided Ports |
||
| 113 | |||
| 114 | When implementing provided ports, there is two main ways of doing it: |
||
| 115 | * Using an anonymous instance of the interface. |
||
| 116 | * By implementing the interface directly with the component implementation. |
||
| 117 | |||
| 118 | Using an anonymous class is as follow: |
||
| 119 | <pre> |
||
| 120 | public class MySimpleComponentImpl extends MySimpleComponent { |
||
| 121 | |||
| 122 | @Override |
||
| 123 | protected AnotherJavaInterface make_p1() { |
||
| 124 | return new AnotherJavaInterface() { |
||
| 125 | @Override |
||
| 126 | public Integer test() { |
||
| 127 | return 10; |
||
| 128 | } |
||
| 129 | }; |
||
| 130 | } |
||
| 131 | |||
| 132 | } |
||
| 133 | </pre> |
||
| 134 | |||
| 135 | Implementing the interface is as follow: |
||
| 136 | <pre> |
||
| 137 | public class MySimpleComponentImpl extends MySimpleComponent implements AnotherJavaInterface { |
||
| 138 | |||
| 139 | @Override |
||
| 140 | public Integer test() { |
||
| 141 | return 10; |
||
| 142 | } |
||
| 143 | |||
| 144 | @Override |
||
| 145 | protected AnotherJavaInterface make_p1() { |
||
| 146 | return this; |
||
| 147 | } |
||
| 148 | } |
||
| 149 | </pre> |
||
| 150 | |||
| 151 | h2. Reducing References to Shared Objects between Components |
||
| 152 | |||
| 153 | Components expose their required functionalities through explicit ports bound when composition is done. |
||
| 154 | This is very different from objects that must be given directly an object providing a required functionality. |
||
| 155 | |||
| 156 | An error that must be avoided when defining a component is to express a dependency to a functionality by requiring objects to be passed to their implementation constructor or by instantiating other objects in their implementation. |
||
| 157 | It is better to explicit such dependencies through required ports. |
||
| 158 | |||
| 159 | Of course this rule can be bent when the functionality is really internal to the component implementation and when it has nothing to do with the architecture the component is part of. |
||
| 160 | But it is a good practice to explicit required functionalities like this for facilitating future evolution. |