You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _drafts/2019-10-21-dry.md
+353-3Lines changed: 353 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,14 +21,364 @@ Nie warto na siłę próbować implementować zasadę `DRY` ponieważ może się
21
21
## Funkcje
22
22
Oczywistym sposobem na zmniejszenie ilości powtórzeń jest umieszczanie bloku kodu w ciele funkcji, która może zostać użyta wielokrotnie w wielu miejscach aplikacji. Należy także wziąć pod uwagę czy istnieje możliwość i zachodzi sens szukania rozwiązania generalnego poprzez funkcję z parametrami wejściowymi.
val pattern = Pattern.compile("^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{6,}$")
74
+
val matcher = pattern.matcher(password)
75
+
return matcher.matches()
76
+
}
77
+
78
+
//some body
79
+
}
80
+
{% endhighlight %}
81
+
82
+
Walidacja hasła zachodzi w ten sam sposób w conajmniej dwóch miejscach: `RegisterView`, `ChangePasswordView`. Ponadto widok rejestracji sprawdza poprawność wpisanego adresu email. Można przypuszczać, że istnieje spora szansa na ponowne wykorzystanie metod walidacyjnych w innych miejscach aplikacji. W związku z tym warto przenieść metody walidacyjne do jednej klasy pomocniczej `Validator` dodatkowo zachowując ich spójność w całym kodzie.
Warto rozważyć zastosowanie zarówno stałych lokalnych jak i globalnych, które poza redukcją powielania zwiększają czytelność kodu w wyniku zastępienia niekoniecznie zrozumiałych nazw zmiennych.
26
144
145
+
{% highlight kotlin %}
146
+
class DateUtils {
147
+
148
+
fun getDaysInMiliseconds(miliseconds: Long): Long {
149
+
return miliseconds / 1000 * 60 * 60 * 24
150
+
}
151
+
152
+
fun getMilisecondsInDays(days: Long): Long {
153
+
return days * 1000 * 60 * 60 * 24
154
+
}
155
+
}
156
+
{% endhighlight %}
157
+
158
+
Metody klasy pomocnicznej `DateUtils` wykorzystują w swoich obliczeniach mnożnik reprezentujący ilość milisekund w dniu. Aby zaoszczędzić powielenia kodu i uniknąć pomyłki należy stworzyć stałą `MILISECONDS_IN_DAYS` i wykorzystać ją w metodach.
159
+
160
+
{% highlight kotlin %}
161
+
class DateUtils {
162
+
163
+
companion object {
164
+
const val MILISECONDS_IN_DAYS: Long = 1000 * 60 * 60 * 24
165
+
}
166
+
167
+
fun getDaysInMiliseconds(miliseconds: Long): Long {
168
+
return miliseconds / MILISECONDS_IN_DAYS
169
+
}
170
+
171
+
fun getMilisecondsInDays(days: Long): Long {
172
+
return days * MILISECONDS_IN_DAYS
173
+
}
174
+
}
175
+
{% endhighlight %}
176
+
27
177
## Typy
28
178
Wykonanie żądanej operacji może się wiązać z przekazaniem argumentów i zwróceniem wyniku, które mogą się składać z kilku obiektów. W takiej sytuacji zasadnym może być stworzenie nowego typu danych zawierającego obiekty typów argumentów wejściowych lub wyjściowych.
29
179
30
-
## Polimorfizm
31
-
Polimorfizm umożliwia spójne wykorzystanie elementów na kilka różnych sposobów niezależnie od ich typów za pomocą jednego wspólnego interfejsu. Eliminuje instrukcje warunkowe zależne od typu i redukuje powtarzający się kod za pomocą m.in. mechanizmu dziedziczenia.
180
+
{% highlight kotlin %}
181
+
class PlayerManager {
182
+
183
+
fun changeNick(id: Long, newNick: String) {
184
+
//put newNick to database or send to server
185
+
}
186
+
187
+
fun getLevel(points: Int): String {
188
+
return when(points) {
189
+
in 0..99 -> "BEGINNER"
190
+
in 100..300 -> "JUNIOR"
191
+
in 300..599 -> "ADVANCED"
192
+
else -> "MASTER"
193
+
}
194
+
}
195
+
196
+
fun increasePoints(id: Long, points: Int, percent: Int) {
197
+
val newPoints = points + points * percent
198
+
updateLevel(id, newPoints)
199
+
//put newPoints to database or send to server using id
200
+
}
201
+
202
+
private fun updateLevel(id: Long, points: Int) {
203
+
val newLevel = getLevel(points)
204
+
//put newLevel to database or send to server using id
205
+
}
206
+
}
207
+
{% endhighlight %}
208
+
209
+
Metody klasy `PlayerManager` operują na wielu parametrach różnego typu w celu zastosowania operacji na danych zawodnika. Wymienione argumenty są ze sobą logicznie powiązane i mogą składać się na pola klasy `Player`. Wówczas część odpowiedzialności z klasy `PlayerManager` mogłaby zostać przeniesiona do klasy `Player`.
210
+
211
+
{% highlight kotlin %}
212
+
class PlayerManager {
213
+
214
+
fun changeNick(player: Player, newNick: String) {
215
+
player.nick = newNick
216
+
//put player to database or send to server
217
+
}
218
+
219
+
fun increasePoints(player: Player, percent: Int) {
220
+
player.increasePointsByPercent(percent)
221
+
//put player to database or send to server
222
+
}
223
+
}
224
+
225
+
data class Player(val id: Long, var nick: String, var points: Int, var level: Level) {
226
+
227
+
init {
228
+
updateLevel()
229
+
}
230
+
231
+
fun increasePointsByPercent(percent: Int) {
232
+
points += points * percent
233
+
updateLevel()
234
+
}
235
+
236
+
fun updateLevel() {
237
+
level = when(points) {
238
+
in 0..99 -> Level.BEGINNER
239
+
in 100..300 -> Level.JUNIOR
240
+
in 300..599 -> Level.ADVANCED
241
+
else -> Level.MASTER
242
+
}
243
+
}
244
+
245
+
enum class Level(value: String) {
246
+
BEGINNER("BEGINNER"),
247
+
JUNIOR("JUNIOR"),
248
+
ADVANCED("ADVANCED"),
249
+
MASTER("MASTER")
250
+
}
251
+
}
252
+
{% endhighlight %}
253
+
254
+
## Polimorfizm i dziedziczenie
255
+
Polimorfizm umożliwia spójne wykorzystanie elementów na kilka różnych sposobów niezależnie od ich typów za pomocą jednego wspólnego interfejsu. Eliminuje instrukcje warunkowe zależne od typu i redukuje powtarzający się kod. Mechanizm dziedziczenia pozwala na wykorzystanie współdzielonego kodu typu bazowego przez jego podtypy.
256
+
257
+
{% highlight kotlin %}
258
+
class Book(val index: Long, val title: String, val description: String, val year: Int,
259
+
val author: String, val topics: List<String>) {
260
+
261
+
fun getSummary(): String {
262
+
return "$title ($year) \n $description"
263
+
}
264
+
265
+
fun print() {
266
+
//get Book from database by index and print to file
267
+
}
268
+
}
269
+
270
+
class Article(val index: Long, val title: String, val description: String, val year: Int,
271
+
val author: String, val pages: Int) {
272
+
273
+
fun getSummary(): String {
274
+
return "$title ($year) \n $description"
275
+
}
276
+
277
+
fun print() {
278
+
//get Article from database by index and print to file
279
+
}
280
+
}
281
+
282
+
class Film(val index: Long, val title: String, val description: String, val year: Int,
283
+
val director: String, val actors: List<Actor>, val duration: Int) {
284
+
285
+
fun getSummary(): String {
286
+
return "$title ($year) \n $description"
287
+
}
288
+
}
289
+
290
+
class Music(val index: Long, val title: String, val description: String, val year: Int,
291
+
val band: String, val duration: Int) {
292
+
293
+
fun getSummary(): String {
294
+
return "$title ($year) \n $description"
295
+
}
296
+
}
297
+
{% endhighlight %}
298
+
299
+
Klasy `Book`, `Article`, `Film`, `Music` posiadają właściwości i cechy wspólne, które powinny zostać wyabstrachowane do typu wspólnego `Item`. Ponadto klient wykorzystujący te obiekty jest zmuszony do sprawdzania typów i rzutowania, aby dokonać wydruku elementów papierowych. Zachowanie opisujące możliwość wydruku może zostać przeniesione do interfejsu `Printable` i jego implementacji w wybranych klasach.
300
+
301
+
{% highlight kotlin %}
302
+
class Book(index: Long, title: String, description: String, year: Int,
303
+
val author: String, val topics: List<String>) : Item(index, title, description, year), Printable {
304
+
305
+
override fun print() {
306
+
//get Book from database by index and print to file
307
+
}
308
+
}
309
+
310
+
class Article(index: Long, title: String, description: String, year: Int,
311
+
val author: String, val pages: Int) : Item(index, title, description, year), Printable {
312
+
313
+
override fun print() {
314
+
//get Article from database by index and print to file
315
+
}
316
+
}
317
+
318
+
abstract class Item (val index: Long, val title: String, val description: String, val year: Int) {
319
+
320
+
fun getSummary(): String {
321
+
return "$title ($year) \n $description"
322
+
}
323
+
}
324
+
325
+
class Film(index: Long, title: String, description: String, year: Int,
326
+
val director: String, val actors: List<Actor>, val duration: Int) : Item(index, title, description, year)
327
+
328
+
class Music(index: Long, title: String, description: String, year: Int,
329
+
val band: String, val duration: Int) : Item(index, title, description, year)
330
+
331
+
interface Printable {
332
+
333
+
fun print()
334
+
}
335
+
{% endhighlight %}
32
336
33
337
## Moduły
34
-
Dzielenie kodu na moduły umożliwia nie tylko wyróżnienie części logicznych i funkcjonalnych aplikacji, ale może ułatwić ponowne użycie danej funkcjonalności w innym projekcie. W szczególności są to zewnętrzne biblioteki i wtyczki.
338
+
Dzielenie kodu na moduły umożliwia nie tylko wyróżnienie części logicznych i funkcjonalnych aplikacji, ale może ułatwić ponowne użycie danej funkcjonalności w innym projekcie. W szczególności są to zewnętrzne biblioteki i wtyczki.
339
+
340
+
{% highlight kotlin %}
341
+
class Calculator {
342
+
343
+
fun sqrt(value: Double): Double {
344
+
return value * value
345
+
}
346
+
347
+
fun doubleSqrt(value: Double): Double {
348
+
return 2 * sqrt(value)
349
+
}
350
+
351
+
fun pow(value: Double, exponent: Int): Double {
352
+
return if(exponent == 0)
353
+
1.0
354
+
else {
355
+
var result = value
356
+
for(i in exponent downTo 1) {
357
+
result *= value
358
+
}
359
+
result
360
+
}
361
+
}
362
+
363
+
fun doublePow(value: Double, exponent: Int): Double {
364
+
return 2 * pow(value, exponent)
365
+
}
366
+
}
367
+
{% endhighlight %}
368
+
369
+
Klasa `Calculator` dostarcza zbiór metod wykonujących obliczenia matematyczne. Część definicji zawiera się jednak w pakiecie matematycznym `Math` w związku z czym mogą one zostać wykorzystane zamiast autorskiej implementacji.
370
+
371
+
{% highlight kotlin %}
372
+
class Calculator {
373
+
374
+
//use Math module instead of own functions
375
+
376
+
fun doubleSqrt(value: Double): Double {
377
+
return 2 * Math.sqrt(value)
378
+
}
379
+
380
+
fun doublePow(value: Double, exponent: Int): Double {
0 commit comments