{ Color.Gray };
38 | break;
39 | }
40 | return result;
41 | }
42 |
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch05/buildandsendmail/v2/BuildAndSendMail.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch05.buildandsendmail.v2;
2 |
3 | @SuppressWarnings("unused")
4 | public class BuildAndSendMail {
5 |
6 | // tag::buildAndSendMail[]
7 | public void buildAndSendMail(MailMan m, MailAddress mAddress,
8 | MailBody mBody) {
9 | // Build the mail
10 | Mail mail = new Mail(mAddress, mBody);
11 | // Send the mail
12 | m.sendMail(mail);
13 | }
14 |
15 | private class Mail {
16 | private MailAddress address;
17 | private MailBody body;
18 |
19 | private Mail(MailAddress mAddress, MailBody mBody) {
20 | this.address = mAddress;
21 | this.body = mBody;
22 | }
23 | }
24 |
25 | private class MailBody {
26 | String subject;
27 | MailMessage message;
28 |
29 | public MailBody(String subject, MailMessage message) {
30 | this.subject = subject;
31 | this.message = message;
32 | }
33 | }
34 |
35 | private class MailAddress {
36 | private String mId;
37 |
38 | private MailAddress(String firstName, String lastName,
39 | String division) {
40 | this.mId = firstName.charAt(0) + "." + lastName.substring(0, 7)
41 | + "@"
42 | + division.substring(0, 5) + ".compa.ny";
43 | }
44 | }
45 | // end::buildAndSendMail[]
46 |
47 | private MailMessage formatMessage(MailFont font, String string) {
48 | return null;
49 | }
50 |
51 | private class MailMan {
52 | public void send(String mId, String subject, MailMessage mMessage) {}
53 | public void sendMail(Mail mail) {}
54 | }
55 |
56 | private class MailFont {}
57 |
58 | private class MailMessage {}
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch02/v1/BoardFactory.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch02.v1;
2 |
3 | public class BoardFactory {
4 | // tag::createBoard[]
5 | public Board createBoard(Square[][] grid) {
6 | assert grid != null;
7 |
8 | Board board = new Board(grid);
9 |
10 | int width = board.getWidth();
11 | int height = board.getHeight();
12 | for (int x = 0; x < width; x++) {
13 | for (int y = 0; y < height; y++) {
14 | Square square = grid[x][y];
15 | for (Direction dir : Direction.values()) {
16 | setLink(square, dir, x, y, width, height, grid);
17 | }
18 | }
19 | }
20 |
21 | return board;
22 | }
23 | // end::createBoard[]
24 |
25 | // tag::setLink[]
26 | private void setLink(Square square, Direction dir, int x, int y, int width,
27 | int height, Square[][] grid) {
28 | int dirX = (width + x + dir.getDeltaX()) % width;
29 | int dirY = (height + y + dir.getDeltaY()) % height;
30 | Square neighbour = grid[dirX][dirY];
31 | square.link(neighbour, dir);
32 | }
33 | // end::setLink[]
34 | }
35 |
36 | class Board {
37 | @SuppressWarnings("unused")
38 | public Board(Square[][] grid) {}
39 |
40 | public int getWidth() {
41 | return 0;
42 | }
43 |
44 | public int getHeight() {
45 | return 0;
46 | }
47 | }
48 |
49 | class Square {
50 | @SuppressWarnings("unused")
51 | public void link(Square neighbour, Direction dir) {}
52 | }
53 |
54 | class Direction {
55 |
56 | public static Direction[] values() {
57 | return null;
58 | }
59 |
60 | public int getDeltaY() {
61 | return 0;
62 | }
63 |
64 | public int getDeltaX() {
65 | return 0;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch02/Employees.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace eu.sig.training.ch02
4 | {
5 | public static class Employees
6 | {
7 | // tag::printDepartmentEmployees[]
8 | public static void PrintDepartmentEmployees(string department)
9 | {
10 | Query q = new Query();
11 | foreach (Employee e in q.AddColumn("FamilyName")
12 | .AddColumn("Initials")
13 | .AddColumn("GivenName")
14 | .AddColumn("AddressLine1")
15 | .AddColumn("ZIPcode")
16 | .AddColumn("City")
17 | .AddTable("EMPLOYEES")
18 | .AddWhere($"EmployeeDep='{department}'")
19 | .Execute())
20 | {
21 | Console.WriteLine($@"
22 | {e.FamilyName}, {e.Initials}
" +
23 | "{e.AddressLine1}
{e.ZipCode}{e.City}
");
24 | }
25 | }
26 | // end::printDepartmentEmployees[]
27 | }
28 |
29 | class Query
30 | {
31 |
32 | public Query AddColumn(string s)
33 | {
34 | return null;
35 | }
36 |
37 | public Employee[] Execute()
38 | {
39 | return null;
40 | }
41 |
42 | public Query AddWhere(string s)
43 | {
44 | return null;
45 | }
46 |
47 | public Query AddTable(string s)
48 | {
49 | return null;
50 | }
51 | }
52 |
53 | class Employee
54 | {
55 |
56 | public string FamilyName { get; set; }
57 |
58 | public string AddressLine1 { get; set; }
59 |
60 | public string ZipCode { get; set; }
61 |
62 | public string City { get; set; }
63 |
64 | public string Initials { get; set; }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch02/Employees.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch02;
2 |
3 | public class Employees {
4 | // tag::printDepartmentEmployees[]
5 | public static void printDepartmentEmployees(String department) {
6 | Query q = new Query();
7 | for (Employee e : q.addColumn("FamilyName")
8 | .addColumn("Initials")
9 | .addColumn("GivenName")
10 | .addColumn("AddressLine1")
11 | .addColumn("ZIPcode")
12 | .addColumn("City")
13 | .addTable("EMPLOYEES")
14 | .addWhere("EmployeeDep='" + department + "'")
15 | .execute()) {
16 | System.out.println("" + e.getAddressLine1()
18 | + "
" + e.getZipCode() + e.getCity() + "");
19 | }
20 | }
21 | // end::printDepartmentEmployees[]
22 | }
23 |
24 | class Query {
25 |
26 | @SuppressWarnings("unused")
27 | public Query addColumn(String string) {
28 | return null;
29 | }
30 |
31 | public Employee[] execute() {
32 | return null;
33 | }
34 |
35 | @SuppressWarnings("unused")
36 | public Query addWhere(String string) {
37 | return null;
38 | }
39 |
40 | @SuppressWarnings("unused")
41 | public Query addTable(String string) {
42 | return null;
43 | }
44 | }
45 |
46 | class Employee {
47 |
48 | public String getFamilyName() {
49 | return null;
50 | }
51 |
52 | public String getAddressLine1() {
53 | return null;
54 | }
55 |
56 | public String getZipCode() {
57 | return null;
58 | }
59 |
60 | public String getCity() {
61 | return null;
62 | }
63 |
64 | public String getInitials() {
65 | return null;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch04/v3/Accounts.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace eu.sig.training.ch04.v3
5 | {
6 |
7 | public static class Accounts
8 | {
9 |
10 | // The Java version of the Account class does not have a string Number as property,
11 | // and the Java edition of the book is already in print. So we add an external
12 | // association of Accounts and their numbers.
13 | public static Dictionary ACCOUNTS = new Dictionary();
14 | public static Dictionary NUMBERS = new Dictionary();
15 |
16 | public static CheckingAccount FindAcctByNumber(string number)
17 | {
18 | var myAccount = ACCOUNTS[number];
19 | if (myAccount is CheckingAccount)
20 | {
21 | return (CheckingAccount)myAccount;
22 | }
23 | else
24 | {
25 | throw new BusinessException("Not a checking account.");
26 | }
27 | }
28 |
29 | public static T MakeAccount(string number) where T : Account, new()
30 | {
31 | var myAccount = new T();
32 | ACCOUNTS[number] = myAccount;
33 | NUMBERS[myAccount] = number;
34 | return myAccount;
35 | }
36 |
37 | public static string GetAccountNumber(Account acct)
38 | {
39 | return NUMBERS[acct];
40 | }
41 |
42 | // tag::isValid[]
43 | public static bool IsValid(string number)
44 | {
45 | int sum = 0;
46 | for (int i = 0; i < number.Length; i++)
47 | {
48 | sum = sum + (9 - i) * (int)Char.GetNumericValue(number[i]);
49 | }
50 | return sum % 11 == 0;
51 | }
52 | // end::isValid[]
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch06/userservice/v3/UserService.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch06.userservice.v3;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import eu.sig.training.ch06.userservice.NotificationType;
7 | import eu.sig.training.ch06.userservice.User;
8 | import eu.sig.training.ch06.userservice.UserInfo;
9 |
10 | @SuppressWarnings("unused")
11 | // tag::UserService[]
12 | public class UserService {
13 | public User loadUser(String userId) {
14 | // ...
15 | // end::UserService[]
16 | return new User();
17 | // tag::UserService[]
18 | }
19 |
20 | public boolean doesUserExist(String userId) {
21 | // ...
22 | // end::UserService[]
23 | return true;
24 | // tag::UserService[]
25 | }
26 |
27 | public User changeUserInfo(UserInfo userInfo) {
28 | // ...
29 | // end::UserService[]
30 | return new User();
31 | // tag::UserService[]
32 | }
33 |
34 | public List getNotificationTypes(User user) {
35 | // ...
36 | // end::UserService[]
37 | return new ArrayList();
38 | // tag::UserService[]
39 | }
40 |
41 | public void registerForNotifications(User user, NotificationType type) {
42 | // ...
43 | }
44 |
45 | public void unregisterForNotifications(User user, NotificationType type) {
46 | // ...
47 | }
48 |
49 | public List searchUsers(UserInfo userInfo) {
50 | // ...
51 | // end::UserService[]
52 | return new ArrayList();
53 | // tag::UserService[]
54 | }
55 |
56 | public void blockUser(User user) {
57 | // ...
58 | }
59 |
60 | public List getAllBlockedUsers() {
61 | // ...
62 | // end::UserService[]
63 | return new ArrayList();
64 | // tag::UserService[]
65 | }
66 | }
67 | // end::UserSerice[]
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch02/v1/BoardFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace eu.sig.training.ch02.v1
4 | {
5 | public class BoardFactory
6 | {
7 | // tag::createBoard[]
8 | public Board CreateBoard(Square[,] grid)
9 | {
10 | Debug.Assert(grid != null);
11 |
12 | Board board = new Board(grid);
13 |
14 | int width = board.Width;
15 | int height = board.Height;
16 | for (int x = 0; x < width; x++)
17 | {
18 | for (int y = 0; y < height; y++)
19 | {
20 | Square square = grid[x, y];
21 | foreach (Direction dir in Direction.Values)
22 | {
23 | SetLink(square, dir, x, y, width, height, grid);
24 | }
25 | }
26 | }
27 |
28 | return board;
29 | }
30 | // end::createBoard[]
31 |
32 | // tag::setLink[]
33 | private void SetLink(Square square, Direction dir, int x, int y,
34 | int width, int height, Square[,] grid)
35 | {
36 | int dirX = (width + x + dir.DeltaX) % width;
37 | int dirY = (height + y + dir.DeltaY) % height;
38 | Square neighbour = grid[dirX, dirY];
39 | square.Link(neighbour, dir);
40 | }
41 | // end::setLink[]
42 | }
43 |
44 | public class Board
45 | {
46 | public Board(Square[,] grid) { }
47 |
48 | public int Width { get; set; }
49 | public int Height { get; set; }
50 | }
51 |
52 | public class Square
53 | {
54 | public void Link(Square neighbour, Direction dir) { }
55 | }
56 |
57 | public class Direction
58 | {
59 |
60 | public static Direction[] Values { get; set; }
61 |
62 | public int DeltaY { get; set; }
63 |
64 | public int DeltaX { get; set; }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch11/MagicConstants.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch11;
2 |
3 | public class MagicConstants {
4 |
5 | public class Customer {
6 | private final int age;
7 |
8 | public Customer(int age) {
9 | this.age = age;
10 | }
11 |
12 | public int getAge() {
13 | return age;
14 | }
15 | }
16 |
17 | public class UseMagicConstants {
18 |
19 | // tag::calculateFareMagicConstants[]
20 | float calculateFare(Customer c, long distance) {
21 | float travelledDistanceFare = distance * 0.10f;
22 | if (c.getAge() < 12) {
23 | travelledDistanceFare *= 0.25f;
24 | } else
25 | if (c.getAge() >= 65) {
26 | travelledDistanceFare *= 0.5f;
27 | }
28 | return 3.00f + travelledDistanceFare;
29 | }
30 | // end::calculateFareMagicConstants[]
31 |
32 | }
33 |
34 | public class DoNotUseMagicConstants {
35 | // tag::calculateFareDoNotUseMagicConstants[]
36 | private static final float BASE_RATE = 3.00f;
37 | private static final float FARE_PER_KM = 0.10f;
38 | private static final float DISCOUNT_RATE_CHILDREN = 0.25f;
39 | private static final float DISCOUNT_RATE_ELDERLY = 0.5f;
40 | private static final int MAXIMUM_AGE_CHILDREN = 12;
41 | private static final int MINIMUM_AGE_ELDERLY = 65;
42 |
43 | float calculateFare(Customer c, long distance) {
44 | float travelledDistanceFare = distance * FARE_PER_KM;
45 | if (c.getAge() < MAXIMUM_AGE_CHILDREN) {
46 | travelledDistanceFare *= DISCOUNT_RATE_CHILDREN;
47 | } else
48 | if (c.getAge() >= MINIMUM_AGE_ELDERLY) {
49 | travelledDistanceFare *= DISCOUNT_RATE_ELDERLY;
50 | }
51 | return BASE_RATE + travelledDistanceFare;
52 | }
53 | // end::calculateFareDoNotUseMagicConstants[]
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch06/userservice/v3/UserService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace eu.sig.training.ch06.userservice.v3
4 | {
5 |
6 | // tag::UserService[]
7 | public class UserService
8 | {
9 | public User LoadUser(string userId)
10 | {
11 | // ...
12 | // end::UserService[]
13 | return new User();
14 | // tag::UserService[]
15 | }
16 |
17 | public bool DoesUserExist(string userId)
18 | {
19 | // ...
20 | // end::UserService[]
21 | return true;
22 | // tag::UserService[]
23 | }
24 |
25 | public User ChangeUserInfo(UserInfo userInfo)
26 | {
27 | // ...
28 | // end::UserService[]
29 | return new User();
30 | // tag::UserService[]
31 | }
32 |
33 | public List GetNotificationTypes(User user)
34 | {
35 | // ...
36 | // end::UserService[]
37 | return new List();
38 | // tag::UserService[]
39 | }
40 |
41 | public void RegisterForNotifications(User user, NotificationType type)
42 | {
43 | // ...
44 | }
45 |
46 | public void UnregisterForNotifications(User user, NotificationType type)
47 | {
48 | // ...
49 | }
50 |
51 | public List SearchUsers(UserInfo userInfo)
52 | {
53 | // ...
54 | // end::UserService[]
55 | return new List();
56 | // tag::UserService[]
57 | }
58 |
59 | public void BlockUser(User user)
60 | {
61 | // ...
62 | }
63 |
64 | public List GetAllBlockedUsers()
65 | {
66 | // ...
67 | // end::UserService[]
68 | return new List();
69 | // tag::UserService[]
70 | }
71 | }
72 | // end::UserSerice[]
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch02/v2/BoardFactory.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch02.v2;
2 |
3 | public class BoardFactory {
4 | // tag::createBoard[]
5 | public Board createBoard(Square[][] grid) {
6 | return new BoardCreator(grid).create();
7 | }
8 | // end::createBoard[]
9 | }
10 |
11 | // tag::BoardCreator[]
12 | class BoardCreator {
13 | private Square[][] grid;
14 | private Board board;
15 | private int width;
16 | private int height;
17 |
18 | BoardCreator(Square[][] grid) {
19 | assert grid != null;
20 | this.grid = grid;
21 | this.board = new Board(grid);
22 | this.width = board.getWidth();
23 | this.height = board.getHeight();
24 | }
25 |
26 | Board create() {
27 | for (int x = 0; x < width; x++) {
28 | for (int y = 0; y < height; y++) {
29 | Square square = grid[x][y];
30 | for (Direction dir : Direction.values()) {
31 | setLink(square, dir, x, y);
32 | }
33 | }
34 | }
35 | return this.board;
36 | }
37 |
38 | private void setLink(Square square, Direction dir, int x, int y) {
39 | int dirX = (width + x + dir.getDeltaX()) % width;
40 | int dirY = (height + y + dir.getDeltaY()) % height;
41 | Square neighbour = grid[dirX][dirY];
42 | square.link(neighbour, dir);
43 | }
44 | }
45 |
46 | // end::BoardCreator[]
47 |
48 | class Board {
49 | @SuppressWarnings("unused")
50 | public Board(Square[][] grid) {}
51 |
52 | public int getWidth() {
53 | return 0;
54 | }
55 |
56 | public int getHeight() {
57 | return 0;
58 | }
59 | }
60 |
61 | class Square {
62 | @SuppressWarnings("unused")
63 | public void link(Square neighbour, Direction dir) {}
64 | }
65 |
66 | class Direction {
67 |
68 | public static Direction[] values() {
69 | return null;
70 | }
71 |
72 | public int getDeltaY() {
73 | return 0;
74 | }
75 |
76 | public int getDeltaX() {
77 | return 0;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch05/buildandsendmail/v2/BuildAndSendMail.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace eu.sig.training.ch05.buildandsendmail.v2
3 | {
4 | public class BuildAndSendMail
5 | {
6 |
7 | // tag::buildAndSendMail[]
8 | public void DoBuildAndSendMail(MailMan m, MailAddress mAddress,
9 | MailBody mBody)
10 | {
11 | // Build the mail
12 | Mail mail = new Mail(mAddress, mBody);
13 | // Send the mail
14 | m.SendMail(mail);
15 | }
16 |
17 | public class Mail
18 | {
19 | public MailAddress Address { get; set; }
20 | public MailBody Body { get; set; }
21 |
22 | public Mail(MailAddress mAddress, MailBody mBody)
23 | {
24 | this.Address = mAddress;
25 | this.Body = mBody;
26 | }
27 | }
28 |
29 | public class MailBody
30 | {
31 | public string Subject { get; set; }
32 | public MailMessage Message { get; set; }
33 |
34 | public MailBody(string subject, MailMessage message)
35 | {
36 | this.Subject = subject;
37 | this.Message = message;
38 | }
39 | }
40 |
41 | public class MailAddress
42 | {
43 | public string MsgId { get; private set; }
44 |
45 | public MailAddress(string firstName, string lastName,
46 | string division)
47 | {
48 | this.MsgId = $"{firstName[0]}.{lastName.Substring(0, 7)}" +
49 | $"@{division.Substring(0, 5)}.compa.ny";
50 | }
51 | }
52 | // end::buildAndSendMail[]
53 |
54 | public MailMessage FormatMessage(MailFont font, string s)
55 | {
56 | return null;
57 | }
58 |
59 | public class MailMan
60 | {
61 | public void Send(string mId, string subject, MailMessage mMessage) { }
62 | public void SendMail(Mail mail) { }
63 | }
64 |
65 | public class MailFont { }
66 |
67 | public class MailMessage { }
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch03/FlagFactoryOops.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch03;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 |
6 | public class FlagFactoryOops {
7 | private static class Color extends java.awt.Color {
8 | private static final long serialVersionUID = 1L;
9 | public static Color BLACK = getColor(java.awt.Color.BLACK);
10 | public static Color BLUE = getColor(java.awt.Color.BLUE);
11 | public static Color RED = getColor(java.awt.Color.RED);
12 | public static Color GREEN = getColor(java.awt.Color.GREEN);
13 | public static Color GRAY = getColor(java.awt.Color.GRAY);
14 | public static Color LIGHT_BLUE = getColor(new java.awt.Color(0, 163, 224));
15 | public static Color WHITE = getColor(java.awt.Color.WHITE);
16 | public static Color YELLOW = getColor(java.awt.Color.YELLOW);
17 |
18 | public Color(java.awt.Color realColor) {
19 | super(realColor.getRGB());
20 | }
21 |
22 | public static Color getColor(java.awt.Color c) {
23 | return new Color(c);
24 | }
25 | }
26 |
27 | public List getFlagColors(Nationality nationality) {
28 | List result;
29 | switch (nationality) {
30 | // tag::getFlag[]
31 | case DUTCH:
32 | result = Arrays.asList(Color.RED, Color.WHITE, Color.BLUE);
33 | case LUXEMBOURGER:
34 | result = Arrays.asList(Color.RED, Color.WHITE, Color.LIGHT_BLUE);
35 | break;
36 | case GERMAN:
37 | // end::getFlag[]
38 | result = Arrays.asList(Color.BLACK, Color.RED, Color.YELLOW);
39 | break;
40 | case BELGIAN:
41 | result = Arrays.asList(Color.BLACK, Color.YELLOW, Color.RED);
42 | break;
43 | case FRENCH:
44 | result = Arrays.asList(Color.BLUE, Color.WHITE, Color.RED);
45 | break;
46 | case ITALIAN:
47 | result = Arrays.asList(Color.GREEN, Color.WHITE, Color.RED);
48 | break;
49 | case UNCLASSIFIED:
50 | default:
51 | result = Arrays.asList(Color.GRAY);
52 | break;
53 | }
54 | return result;
55 | }
56 |
57 | }
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch11/MagicConstants.cs:
--------------------------------------------------------------------------------
1 | namespace eu.sig.training.ch11
2 | {
3 | public class MagicConstants
4 | {
5 |
6 | public class Customer
7 | {
8 |
9 | public Customer(int age)
10 | {
11 | this.Age = age;
12 | }
13 |
14 | public int Age { get; set; }
15 | }
16 |
17 | public class UseMagicConstants
18 | {
19 |
20 | // tag::calculateFareMagicConstants[]
21 | float CalculateFare(Customer c, long distance)
22 | {
23 | float travelledDistanceFare = distance * 0.10f;
24 | if (c.Age < 12)
25 | {
26 | travelledDistanceFare *= 0.25f;
27 | }
28 | else
29 | if (c.Age >= 65)
30 | {
31 | travelledDistanceFare *= 0.5f;
32 | }
33 | return 3.00f + travelledDistanceFare;
34 | }
35 | // end::calculateFareMagicConstants[]
36 |
37 | }
38 |
39 | public class DoNotUseMagicConstants
40 | {
41 | // tag::calculateFareDoNotUseMagicConstants[]
42 | private static readonly float BASE_RATE = 3.00f;
43 | private static readonly float FARE_PER_KM = 0.10f;
44 | private static readonly float DISCOUNT_RATE_CHILDREN = 0.25f;
45 | private static readonly float DISCOUNT_RATE_ELDERLY = 0.5f;
46 | private static readonly int MAXIMUM_AGE_CHILDREN = 12;
47 | private static readonly int MINIMUM_AGE_ELDERLY = 65;
48 |
49 | float CalculateFare(Customer c, long distance)
50 | {
51 | float travelledDistanceFare = distance * FARE_PER_KM;
52 | if (c.Age < MAXIMUM_AGE_CHILDREN)
53 | {
54 | travelledDistanceFare *= DISCOUNT_RATE_CHILDREN;
55 | }
56 | else
57 | if (c.Age >= MINIMUM_AGE_ELDERLY)
58 | {
59 | travelledDistanceFare *= DISCOUNT_RATE_ELDERLY;
60 | }
61 | return BASE_RATE + travelledDistanceFare;
62 | }
63 | // end::calculateFareDoNotUseMagicConstants[]
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/eu/sig/training/ch10/PerfectPictureTest.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch10;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import java.awt.Image;
6 | import java.awt.image.BufferedImage;
7 | import java.io.File;
8 | import java.io.IOException;
9 |
10 | import javax.imageio.ImageIO;
11 |
12 | import org.junit.Test;
13 |
14 | import eu.sig.training.ch06.simpledigitalcamera.SimpleDigitalCamera;
15 | import eu.sig.training.ch10.PerfectPicture;
16 |
17 | public class PerfectPictureTest {
18 |
19 | // tag::testDayPicture[]
20 | @Test
21 | public void testDayPicture() throws IOException {
22 | BufferedImage image =
23 | ImageIO.read(new File("src/test/resources/VanGoghSunflowers.jpg"));
24 | DigitalCameraStub cameraStub = new DigitalCameraStub();
25 | cameraStub.testImage = image;
26 | PerfectPicture.camera = cameraStub;
27 | assertEquals(image, new PerfectPicture().takePerfectPicture(12));
28 | }
29 | // end::testDayPicture[]
30 |
31 | // tag::testNightPicture[]
32 | @Test
33 | public void testNightPicture() throws IOException {
34 | BufferedImage image =
35 | ImageIO.read(new File("src/test/resources/VanGoghStarryNight.jpg"));
36 | DigitalCameraMock cameraMock = new DigitalCameraMock();
37 | cameraMock.testImage = image;
38 | PerfectPicture.camera = cameraMock;
39 | assertEquals(image, new PerfectPicture().takePerfectPicture(0));
40 | assertEquals(1, cameraMock.flashOnCounter);
41 | }
42 | // end::testNightPicture[]
43 |
44 | }
45 |
46 | // tag::DigitalCameraStub[]
47 | class DigitalCameraStub implements SimpleDigitalCamera {
48 | public Image testImage;
49 |
50 | public Image takeSnapshot() {
51 | return this.testImage;
52 | }
53 |
54 | public void flashLightOn() {}
55 |
56 | public void flashLightOff() {}
57 | }
58 | // end::DigitalCameraStub[]
59 |
60 | // tag::DigitalCameraMock[]
61 | class DigitalCameraMock implements SimpleDigitalCamera {
62 | public Image testImage;
63 | public int flashOnCounter = 0;
64 |
65 | public Image takeSnapshot() {
66 | return this.testImage;
67 | }
68 |
69 | public void flashLightOn() {
70 | this.flashOnCounter++;
71 | }
72 |
73 | public void flashLightOff() {}
74 | }
75 | // end::DigitalCameraMock[]
76 |
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch02/v2/BoardFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace eu.sig.training.ch02.v2
4 | {
5 | public class BoardFactory
6 | {
7 | // tag::createBoard[]
8 | public Board CreateBoard(Square[,] grid)
9 | {
10 | return new BoardCreator(grid).Create();
11 | }
12 | // end::createBoard[]
13 | }
14 |
15 | // tag::BoardCreator[]
16 | internal class BoardCreator
17 | {
18 | private Square[,] grid;
19 | private Board board;
20 | private int width;
21 | private int height;
22 |
23 | internal BoardCreator(Square[,] grid)
24 | {
25 | Debug.Assert(grid != null);
26 | this.grid = grid;
27 | this.board = new Board(grid);
28 | this.width = board.Width;
29 | this.height = board.Height;
30 | }
31 |
32 | internal Board Create()
33 | {
34 | for (int x = 0; x < width; x++)
35 | {
36 | for (int y = 0; y < height; y++)
37 | {
38 | Square square = grid[x, y];
39 | foreach (Direction dir in Direction.Values)
40 | {
41 | SetLink(square, dir, x, y);
42 | }
43 | }
44 | }
45 | return this.board;
46 | }
47 |
48 | private void SetLink(Square square, Direction dir, int x, int y)
49 | {
50 | int dirX = (width + x + dir.DeltaX) % width;
51 | int dirY = (height + y + dir.DeltaY) % height;
52 | Square neighbour = grid[dirX, dirY];
53 | square.Link(neighbour, dir);
54 | }
55 | }
56 |
57 | // end::BoardCreator[]
58 |
59 | public class Board
60 | {
61 | public Board(Square[,] grid)
62 | {
63 | }
64 |
65 | public int Width { get; set; }
66 |
67 | public int Height { get; set; }
68 | }
69 |
70 | public class Square
71 | {
72 | public void Link(Square neighbour, Direction dir)
73 | {
74 | }
75 | }
76 |
77 | public class Direction
78 | {
79 | public static Direction[] Values { get; set; }
80 |
81 | public int DeltaY { get; set; }
82 |
83 | public int DeltaX { get; set; }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/test/csharp/eu/sig/training/ch10/PerfectPictureTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using System.Drawing;
3 | using eu.sig.training.ch06.simpledigitalcamera;
4 |
5 | namespace eu.sig.training.ch10
6 | {
7 |
8 | [TestFixture]
9 | public class PerfectPictureTest
10 | {
11 |
12 | // tag::testDayPicture[]
13 | [Test]
14 | public void TestDayPicture()
15 | {
16 | Image image =
17 | Image.FromFile("../../../../test/resources/VanGoghSunflowers.jpg");
18 | DigitalCameraStub cameraStub = new DigitalCameraStub();
19 | cameraStub.TestImage = image;
20 | PerfectPicture.camera = cameraStub;
21 | Assert.AreSame(image, new PerfectPicture().TakePerfectPicture(12));
22 | }
23 | // end::testDayPicture[]
24 |
25 | // tag::testNightPicture[]
26 | [Test]
27 | public void TestNightPicture()
28 | {
29 | Image image =
30 | Image.FromFile("../../../../test/resources/VanGoghStarryNight.jpg");
31 | DigitalCameraMock cameraMock = new DigitalCameraMock();
32 | cameraMock.TestImage = image;
33 | PerfectPicture.camera = cameraMock;
34 | Assert.AreSame(image, new PerfectPicture().TakePerfectPicture(0));
35 | Assert.AreEqual(1, cameraMock.FlashOnCounter);
36 | }
37 | // end::testNightPicture[]
38 |
39 | }
40 |
41 | // tag::DigitalCameraStub[]
42 | class DigitalCameraStub : ISimpleDigitalCamera
43 | {
44 | public Image TestImage;
45 |
46 | public Image TakeSnapshot()
47 | {
48 | return this.TestImage;
49 | }
50 |
51 | public void FlashLightOn()
52 | {
53 | }
54 |
55 | public void FlashLightOff()
56 | {
57 | }
58 | }
59 | // end::DigitalCameraStub[]
60 |
61 | // tag::DigitalCameraMock[]
62 | class DigitalCameraMock : ISimpleDigitalCamera
63 | {
64 | public Image TestImage;
65 | public int FlashOnCounter = 0;
66 |
67 | public Image TakeSnapshot()
68 | {
69 | return this.TestImage;
70 | }
71 |
72 | public void FlashLightOn()
73 | {
74 | this.FlashOnCounter++;
75 | }
76 |
77 | public void FlashLightOff()
78 | {
79 | }
80 | }
81 | // end::DigitalCameraMock[]
82 | }
83 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch02/Level.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch02;
2 |
3 | import java.util.List;
4 |
5 | public class Level {
6 | private boolean inProgress;
7 | private final List observers;
8 |
9 | Level(List observers) {
10 | this.observers = observers;
11 | }
12 |
13 | // tag::start[]
14 | public void start() {
15 | if (inProgress) {
16 | return;
17 | }
18 | inProgress = true;
19 | // Update observers if player died:
20 | if (!isAnyPlayerAlive()) {
21 | for (LevelObserver o : observers) {
22 | o.levelLost();
23 | }
24 | }
25 | // Update observers if all pellets eaten:
26 | if (remainingPellets() == 0) {
27 | for (LevelObserver o : observers) {
28 | o.levelWon();
29 | }
30 | }
31 | }
32 | // end::start[]
33 |
34 | @SuppressWarnings("unused")
35 | // tag::updateObservers[]
36 | private void updateObservers() {
37 | // Update observers if player died:
38 | if (!isAnyPlayerAlive()) {
39 | for (LevelObserver o : observers) {
40 | o.levelLost();
41 | }
42 | }
43 | // Update observers if all pellets eaten:
44 | if (remainingPellets() == 0) {
45 | for (LevelObserver o : observers) {
46 | o.levelWon();
47 | }
48 | }
49 | }
50 | // end::updateObservers[]
51 |
52 | @SuppressWarnings("unused")
53 | // tag::updateObserversPlayerDied[]
54 | private void updateObserversPlayerDied() {
55 | if (!isAnyPlayerAlive()) {
56 | for (LevelObserver o : observers) {
57 | o.levelLost();
58 | }
59 | }
60 | }
61 |
62 | // end::updateObserversPlayerDied[]
63 |
64 | @SuppressWarnings("unused")
65 | // tag::updateObserversPelletsEaten[]
66 | private void updateObserversPelletsEaten() {
67 | if (remainingPellets() == 0) {
68 | for (LevelObserver o : observers) {
69 | o.levelWon();
70 | }
71 | }
72 | }
73 | // end::updateObserversPelletsEaten[]
74 |
75 | private int remainingPellets() {
76 | return 0;
77 | }
78 |
79 | private boolean isAnyPlayerAlive() {
80 | return false;
81 | }
82 | }
83 |
84 | class LevelObserver {
85 | public void levelLost() {}
86 | public void levelWon() {}
87 | }
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Building Maintainable Software
2 | ==========
3 |
4 | This is the example code that accompanies _Building Maintainable Software: Ten Guidelines for Future-Proof Code_ by Joost Visser.
5 |
6 | There are currently two editions of _Building Maintainable Software_:
7 | - The Java edition (ISBN print: 978-1-4919-5352-5, ISBN eBook: 978-1-4919-5348-8), available [at the O'Reilly webshop](http://shop.oreilly.com/product/0636920049159.do) and [at Amazon](http://www.amazon.com/Building-Maintainable-Software-Java-Edition-ebook/dp/B01B6WS86I).
8 | - The C# edition, currently submitted as a manuscript to O'Reilly Media.
9 |
10 | [Training videos](http://oreil.ly/1OVw1PM) are also available via O'Reilly Media.
11 |
12 | Both editions are the same except for the language of the code snippets and a bit of language-specific terminology (e.g., 'Eclipse' in the Java edition is 'Visual Studio' in the C# edition).
13 |
14 | Click the Download Zip button to the right to download example code.
15 |
16 | See an error? Report it [here](http://oreilly.com/catalog/errata.csp?isbn=9781491940662) for the Java edition, or simply fork and send us a pull request.
17 |
18 | About The Example Code
19 | -----------
20 |
21 | The example code of the Java edition lives in `src/java` and `src/test/java`. The example code of the C# edition lives in `src/csharp` and `src/test/csharp`. Every `.java` file in `src/java` has a `.cs` file with the same name in `src/csharp` and the other way around. The same is true for the contents of the `src/test` directories.
22 |
23 | For the Java code, there is a `pom.xml` file in the root of this repository. This allows compiling the Java source files and running the unit tests using [Maven](https://maven.apache.org) by executing `mvn test`.
24 |
25 | For the C# code, there is a Visual Studio Solution file in the root of this repository, which references two projects (see the `.csproj` files in `src/csharp` and `src/test/csharp`). We compile the C# code and run the unit tests regularly using [Mono](http://www.mono-project.com) on MacOS and occasionally using Visual Studio.
26 |
27 | Both the Java and the C# editions have been written using O'Reilly's [Atlas](https://atlas.oreilly.com) platform in the [AsciiDoc](http://asciidoc.org) markup language. All code snippets displayed in the books are taken directly from this example code. The parts included in the books are between Java and C# comments of the form `// tag::NameOfTag[]` and `// end::NameOfTag[]`. All code not between such comments is just there to make everything compile and pass unit tests.
28 |
--------------------------------------------------------------------------------
/src/test/java/eu/sig/training/ch03/binarytree/BinaryTreeSearchTest.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch03.binarytree;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertTrue;
5 |
6 | import org.junit.Test;
7 |
8 | public class BinaryTreeSearchTest {
9 |
10 | @Test
11 | public void testSimpleTree() {
12 | BinaryTreeNode root = new BinaryTreeNode(5);
13 | root.insert(3);
14 | root.insert(10);
15 | root.insert(12);
16 |
17 | assertEquals(eu.sig.training.ch03.binarytree.v1.BinaryTreeSearch.calculateDepth(root, 12), 2);
18 | assertEquals(eu.sig.training.ch03.binarytree.v2.BinaryTreeSearch.calculateDepth(root, 12), 2);
19 | assertEquals(eu.sig.training.ch03.binarytree.v3.BinaryTreeSearch.calculateDepth(root, 12), 2);
20 | }
21 |
22 | @Test
23 | public void testDepth0() {
24 | BinaryTreeNode root = new BinaryTreeNode(2);
25 | root.insert(5);
26 | root.insert(1);
27 | root.insert(16);
28 |
29 | assertEquals(eu.sig.training.ch03.binarytree.v1.BinaryTreeSearch.calculateDepth(root, 2), 0);
30 | assertEquals(eu.sig.training.ch03.binarytree.v2.BinaryTreeSearch.calculateDepth(root, 2), 0);
31 | assertEquals(eu.sig.training.ch03.binarytree.v3.BinaryTreeSearch.calculateDepth(root, 2), 0);
32 | }
33 |
34 | @Test
35 | public void testNotInTree() {
36 | BinaryTreeNode root = new BinaryTreeNode(2);
37 | root.insert(5);
38 | root.insert(1);
39 | root.insert(16);
40 | boolean exceptionCaught_v1 = false;
41 | boolean exceptionCaught_v2 = false;
42 | boolean exceptionCaught_v3 = false;
43 |
44 | try {
45 | assertEquals(eu.sig.training.ch03.binarytree.v1.BinaryTreeSearch.calculateDepth(root, 17), 0);
46 | } catch (TreeException e) {
47 | exceptionCaught_v1 = true;
48 | }
49 | try {
50 | assertEquals(eu.sig.training.ch03.binarytree.v2.BinaryTreeSearch
51 | .calculateDepth(root, 17), 0);
52 | } catch (TreeException e) {
53 | exceptionCaught_v2 = true;
54 | }
55 | try {
56 | assertEquals(eu.sig.training.ch03.binarytree.v3.BinaryTreeSearch
57 | .calculateDepth(root, 17), 0);
58 | } catch (TreeException e) {
59 | exceptionCaught_v3 = true;
60 | }
61 | assertTrue(exceptionCaught_v1);
62 | assertTrue(exceptionCaught_v2);
63 | assertTrue(exceptionCaught_v3);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch02/BalancesServlet.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch02;
2 |
3 | import java.io.IOException;
4 | import java.sql.Connection;
5 | import java.sql.DriverManager;
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.util.Properties;
9 |
10 | import javax.servlet.ServletException;
11 | import javax.servlet.http.HttpServlet;
12 | import javax.servlet.http.HttpServletRequest;
13 | import javax.servlet.http.HttpServletResponse;
14 |
15 | public class BalancesServlet extends HttpServlet {
16 | private static final long serialVersionUID = 1L;
17 | private Properties conf;
18 |
19 | @Override
20 | // tag::doGet[]
21 | public void doGet(HttpServletRequest req, HttpServletResponse resp)
22 | throws ServletException, IOException {
23 | resp.setContentType("application/json");
24 | try {
25 | Connection conn = DriverManager.
26 | getConnection(this.conf.getProperty("handler.jdbcurl"));
27 | ResultSet results =
28 | conn.createStatement()
29 | .executeQuery(
30 | "SELECT account, balance FROM ACCTS WHERE id="
31 | + req.getParameter(conf.
32 | getProperty("request.parametername")));
33 | float totalBalance = 0;
34 | resp.getWriter().print("{\"balances\":[");
35 | while (results.next()) {
36 | // Assuming result is 9-digit bank account number,
37 | // validate with 11-test:
38 | int sum = 0;
39 | for (int i = 0; i < results.getString("account")
40 | .length(); i++) {
41 | sum = sum + (9 - i)
42 | * Character.getNumericValue(results.getString(
43 | "account").charAt(i));
44 | }
45 | if (sum % 11 == 0) {
46 | totalBalance += results.getFloat("balance");
47 | resp.getWriter().print(
48 | "{\"" + results.getString("account") + "\":"
49 | + results.getFloat("balance") + "}");
50 | }
51 | if (results.isLast()) {
52 | resp.getWriter().println("],");
53 | } else {
54 | resp.getWriter().print(",");
55 | }
56 | }
57 | resp.getWriter().println("\"total\":" + totalBalance + "}");
58 | } catch (SQLException e) {
59 | System.out.println("SQL exception: " + e.getMessage());
60 | }
61 | }
62 | // end::doGet[]
63 | }
64 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch11/StandardContext.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch11;
2 |
3 | public class StandardContext {
4 |
5 | @SuppressWarnings("unused")
6 | // tag::validateFilterMap[]
7 | private void validateFilterMap(FilterMap filterMap) {
8 | // Validate the proposed filter mapping
9 | String filterName = filterMap.getFilterName();
10 | String[] servletNames = filterMap.getServletNames();
11 | String[] urlPatterns = filterMap.getURLPatterns();
12 | if (findFilterDef(filterName) == null)
13 | throw new IllegalArgumentException(
14 | sm.getString("standardContext.filterMap.name", filterName));
15 |
16 | if (!filterMap.getMatchAllServletNames() &&
17 | !filterMap.getMatchAllUrlPatterns() &&
18 | (servletNames.length == 0) && (urlPatterns.length == 0))
19 | throw new IllegalArgumentException(
20 | sm.getString("standardContext.filterMap.either"));
21 | // FIXME: Older spec revisions may still check this
22 | /*
23 | if ((servletNames.length != 0) && (urlPatterns.length != 0))
24 | throw new IllegalArgumentException
25 | (sm.getString("standardContext.filterMap.either"));
26 | */
27 | for (int i = 0; i < urlPatterns.length; i++) {
28 | if (!validateURLPattern(urlPatterns[i])) {
29 | throw new IllegalArgumentException(
30 | sm.getString("standardContext.filterMap.pattern",
31 | urlPatterns[i]));
32 | }
33 | }
34 | }
35 | // end::validateFilterMap[]
36 |
37 | public class GetStringObject {
38 | public String getString(String string) {
39 | return string;
40 | }
41 |
42 | public String getString(String string,
43 | @SuppressWarnings("unused") Object o) {
44 | return string;
45 | }
46 | }
47 |
48 | private GetStringObject sm = new GetStringObject();
49 |
50 | public class FilterMap {
51 |
52 | public boolean getMatchAllUrlPatterns() {
53 | return false;
54 | }
55 |
56 | public String[] getURLPatterns() {
57 | return null;
58 | }
59 |
60 | public String[] getServletNames() {
61 | return null;
62 | }
63 |
64 | public String getFilterName() {
65 | return null;
66 | }
67 |
68 | public boolean getMatchAllServletNames() {
69 | return false;
70 | }
71 |
72 | }
73 |
74 | private boolean validateURLPattern(
75 | @SuppressWarnings("unused") String string) {
76 | return false;
77 | }
78 |
79 | private Object findFilterDef(
80 | @SuppressWarnings("unused") String filterName) {
81 | return null;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch11/StandardContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace eu.sig.training.ch11 {
4 | public class StandardContext {
5 |
6 | // tag::validateFilterMap[]
7 | private void ValidateFilterMap(FilterMap filterMap) {
8 | // Validate the proposed filter mapping
9 | string filterName = filterMap.GetFilterName();
10 | string[] servletNames = filterMap.GetServletNames();
11 | string[] urlPatterns = filterMap.GetURLPatterns();
12 | if (FindFilterDef(filterName) == null)
13 | throw new Exception(
14 | sm.GetString("standardContext.filterMap.name", filterName));
15 |
16 | if (!filterMap.GetMatchAllServletNames() &&
17 | !filterMap.GetMatchAllUrlPatterns() &&
18 | (servletNames.Length == 0) && (urlPatterns.Length == 0))
19 | throw new Exception(
20 | sm.GetString("standardContext.filterMap.either"));
21 | // FIXME: Older spec revisions may still check this
22 | /*
23 | if ((servletNames.length != 0) && (urlPatterns.length != 0))
24 | throw new IllegalArgumentException
25 | (sm.getString("standardContext.filterMap.either"));
26 | */
27 | for (int i = 0; i < urlPatterns.Length; i++) {
28 | if (!ValidateURLPattern(urlPatterns[i])) {
29 | throw new Exception(
30 | sm.GetString("standardContext.filterMap.pattern",
31 | urlPatterns[i]));
32 | }
33 | }
34 | }
35 | // end::validateFilterMap[]
36 |
37 | public class GetStringObject {
38 | public string GetString(string s) {
39 | return s;
40 | }
41 |
42 | public string GetString(string s, object o) {
43 | return s;
44 | }
45 | }
46 |
47 | private GetStringObject sm = new GetStringObject();
48 |
49 | public class FilterMap {
50 |
51 | public bool GetMatchAllUrlPatterns() {
52 | return false;
53 | }
54 |
55 | public string[] GetURLPatterns() {
56 | return null;
57 | }
58 |
59 | public string[] GetServletNames() {
60 | return null;
61 | }
62 |
63 | public string GetFilterName() {
64 | return null;
65 | }
66 |
67 | public bool GetMatchAllServletNames() {
68 | return false;
69 | }
70 |
71 | }
72 |
73 | private bool ValidateURLPattern(string s) {
74 | return false;
75 | }
76 |
77 | private object FindFilterDef(string filterName) {
78 | return null;
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch02/BalancesServlet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Web;
3 | using System.Data;
4 | using System.Data.SqlClient;
5 | using System.Configuration;
6 |
7 | namespace eu.sig.training.ch02
8 | {
9 | public class BalancesServlet
10 | {
11 | // Visual Studio Code Analysis is right in pointing out that the following method has
12 | // security flaws. However, that's beside the point for this example.
13 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")]
14 | // tag::doGet[]
15 | public void DoGet(HttpRequest req, HttpResponse resp)
16 | {
17 | resp.ContentType = "application/json";
18 | string command = "SELECT account, balance " +
19 | "FROM ACCTS WHERE id=" + req.Params[
20 | ConfigurationManager.AppSettings["request.parametername"]];
21 | SqlDataAdapter dataAdapter = new SqlDataAdapter(command,
22 | ConfigurationManager.AppSettings["handler.serverstring"]);
23 | DataSet dataSet = new DataSet();
24 | dataAdapter.Fill(dataSet, "ACCTS");
25 | DataTable dataTable = dataSet.Tables[0];
26 | try
27 | {
28 | float totalBalance = 0;
29 | int rowNum = 0;
30 | resp.Write("{\"balances\":[");
31 | while (dataTable.Rows.GetEnumerator().MoveNext())
32 | {
33 | rowNum++;
34 | DataRow results = (DataRow)dataTable.Rows.GetEnumerator().Current;
35 | // Assuming result is 9-digit bank account number,
36 | // validate with 11-test:
37 | int sum = 0;
38 | for (int i = 0; i < ((string)results["account"]).Length; i++)
39 | {
40 | sum = sum + (9 - i) *
41 | (int)Char.GetNumericValue(((string)results["account"])[i]);
42 | }
43 | if (sum % 11 == 0)
44 | {
45 | totalBalance += (float)results["balance"];
46 | resp.Write($"{{\"{results["account"]}\":{results["balance"]}}}");
47 | }
48 | if (rowNum == dataTable.Rows.Count)
49 | {
50 | resp.Write("],\n");
51 | }
52 | else
53 | {
54 | resp.Write(",");
55 | }
56 | }
57 | resp.Write($"\"total\":{totalBalance}}}\n");
58 | }
59 | catch (SqlException e)
60 | {
61 | Console.WriteLine($"SQL exception: {e.Message}");
62 | }
63 | }
64 | // end::doGet[]
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/csharp/eu/sig/training/ch03/binarytree/BinaryTreeSearchTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NUnit.Framework;
3 |
4 | namespace eu.sig.training.ch03.binarytree
5 | {
6 | [TestFixture]
7 | public class BinaryTreeSearchTest
8 | {
9 |
10 | [Test]
11 | public void testSimpleTree()
12 | {
13 | BinaryTreeNode root = new BinaryTreeNode(5);
14 | root.Insert(3);
15 | root.Insert(10);
16 | root.Insert(12);
17 |
18 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v1.BinaryTreeSearch.CalculateDepth(root, 12), 2);
19 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v2.BinaryTreeSearch.CalculateDepth(root, 12), 2);
20 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v3.BinaryTreeSearch.CalculateDepth(root, 12), 2);
21 | }
22 |
23 | [Test]
24 | public void testDepth0()
25 | {
26 | BinaryTreeNode root = new BinaryTreeNode(2);
27 | root.Insert(5);
28 | root.Insert(1);
29 | root.Insert(16);
30 |
31 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v1.BinaryTreeSearch.CalculateDepth(root, 2), 0);
32 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v2.BinaryTreeSearch.CalculateDepth(root, 2), 0);
33 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v3.BinaryTreeSearch.CalculateDepth(root, 2), 0);
34 | }
35 |
36 | [Test]
37 | public void testNotInTree()
38 | {
39 | BinaryTreeNode root = new BinaryTreeNode(2);
40 | root.Insert(5);
41 | root.Insert(1);
42 | root.Insert(16);
43 | bool exceptionCaught_v1 = false;
44 | bool exceptionCaught_v2 = false;
45 | bool exceptionCaught_v3 = false;
46 |
47 | #pragma warning disable 168
48 | try
49 | {
50 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v1.BinaryTreeSearch.CalculateDepth(root, 17), 0);
51 | }
52 | catch (TreeException e)
53 | {
54 | exceptionCaught_v1 = true;
55 | }
56 | try
57 | {
58 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v2.BinaryTreeSearch
59 | .CalculateDepth(root, 17), 0);
60 | }
61 | catch (TreeException e)
62 | {
63 | exceptionCaught_v2 = true;
64 | }
65 | try
66 | {
67 | Assert.AreEqual(eu.sig.training.ch03.binarytree.v3.BinaryTreeSearch
68 | .CalculateDepth(root, 17), 0);
69 | }
70 | catch (TreeException e)
71 | {
72 | exceptionCaught_v3 = true;
73 | }
74 | Assert.IsTrue(exceptionCaught_v1);
75 | Assert.IsTrue(exceptionCaught_v2);
76 | Assert.IsTrue(exceptionCaught_v3);
77 | #pragma warning restore 168
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 | eu.sig.training
6 | maintainabilitybook
7 | 0.1-SNAPSHOT
8 |
9 | Software Improvement Group
10 | http://www.sig.eu
11 |
12 |
13 | git@git.atlas.oreilly.com:oreillymedia/sig-project.git
14 |
15 |
16 |
17 | junit
18 | junit
19 | 4.12
20 | test
21 |
22 |
23 | javax.servlet
24 | javax.servlet-api
25 | 3.1.0
26 |
27 |
28 | org.mockito
29 | mockito-core
30 | 1.10.19
31 | test
32 |
33 |
34 | javax.ws.rs
35 | javax.ws.rs-api
36 | 2.0.1
37 |
38 |
39 | org.apache.httpcomponents
40 | httpclient
41 | 4.5.1
42 |
43 |
44 |
45 | ${basedir}/src/java
46 |
47 |
48 | org.apache.maven.plugins
49 | maven-compiler-plugin
50 | 3.3
51 |
52 | 1.7
53 | 1.7
54 |
55 |
56 |
57 | org.apache.maven.plugins
58 | maven-eclipse-plugin
59 | 2.10
60 |
61 | ${basedir}
62 | file:///${basedir}/java_eclipseformat.xml
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-surefire-plugin
68 | 2.18.1
69 |
70 |
71 | **/v1/AccountsTest.java
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | org.apache.maven.plugins
81 | maven-pmd-plugin
82 | 3.5
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/csharp/eu/sig/training/ch02/Level.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace eu.sig.training.ch02
4 | {
5 |
6 | public class Level
7 | {
8 | private bool inProgress;
9 | private readonly IList observers;
10 |
11 | Level(IList observers)
12 | {
13 | this.observers = observers;
14 | }
15 |
16 | // tag::start[]
17 | public void Start()
18 | {
19 | if (inProgress)
20 | {
21 | return;
22 | }
23 | inProgress = true;
24 | // Update observers if player died:
25 | if (!IsAnyPlayerAlive())
26 | {
27 | foreach (LevelObserver o in observers)
28 | {
29 | o.LevelLost();
30 | }
31 | }
32 | // Update observers if all pellets eaten:
33 | if (RemainingPellets() == 0)
34 | {
35 | foreach (LevelObserver o in observers)
36 | {
37 | o.LevelWon();
38 | }
39 | }
40 | }
41 | // end::start[]
42 |
43 | // tag::updateObservers[]
44 | private void UpdateObservers()
45 | {
46 | // Update observers if player died:
47 | if (!IsAnyPlayerAlive())
48 | {
49 | foreach (LevelObserver o in observers)
50 | {
51 | o.LevelLost();
52 | }
53 | }
54 | // Update observers if all pellets eaten:
55 | if (RemainingPellets() == 0)
56 | {
57 | foreach (LevelObserver o in observers)
58 | {
59 | o.LevelWon();
60 | }
61 | }
62 | }
63 | // end::updateObservers[]
64 |
65 | // tag::updateObserversPlayerDied[]
66 | private void UpdateObserversPlayerDied()
67 | {
68 | if (!IsAnyPlayerAlive())
69 | {
70 | foreach (LevelObserver o in observers)
71 | {
72 | o.LevelLost();
73 | }
74 | }
75 | }
76 |
77 | // end::updateObserversPlayerDied[]
78 |
79 | // tag::updateObserversPelletsEaten[]
80 | private void UpdateObserversPelletsEaten()
81 | {
82 | if (RemainingPellets() == 0)
83 | {
84 | foreach (LevelObserver o in observers)
85 | {
86 | o.LevelWon();
87 | }
88 | }
89 | }
90 | // end::updateObserversPelletsEaten[]
91 |
92 | private int RemainingPellets()
93 | {
94 | return 0;
95 | }
96 |
97 | private bool IsAnyPlayerAlive()
98 | {
99 | return false;
100 | }
101 | }
102 |
103 | class LevelObserver
104 | {
105 | public void LevelLost() { }
106 | public void LevelWon() { }
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/java/eu/sig/training/ch05/chartlib/v2/BarChart.java:
--------------------------------------------------------------------------------
1 | package eu.sig.training.ch05.chartlib.v2;
2 |
3 | import java.awt.Graphics;
4 | import java.awt.Point;
5 |
6 | import eu.sig.training.ch05.boardpanel.v2.Rectangle;
7 |
8 | @SuppressWarnings("unused")
9 | // tag::BarChart[]
10 | public class BarChart {
11 | private CategoryItemRendererState state = CategoryItemRendererState.DEFAULT;
12 | private Rectangle graphArea = new Rectangle(new Point(0, 0), 100, 100);
13 | private CategoryPlot plot = CategoryPlot.DEFAULT;
14 | private CategoryAxis domainAxis = CategoryAxis.DEFAULT;
15 | private ValueAxis rangeAxis = ValueAxis.DEFAULT;
16 | private CategoryDataset dataset = CategoryDataset.DEFAULT;
17 |
18 | public BarChart draw(Graphics g) {
19 | // ..
20 | return this;
21 | }
22 |
23 | public ValueAxis getRangeAxis() {
24 | return rangeAxis;
25 | }
26 |
27 | public BarChart setRangeAxis(ValueAxis rangeAxis) {
28 | this.rangeAxis = rangeAxis;
29 | return this;
30 | }
31 |
32 | // More getters and setters.
33 |
34 | // end::BarChart[]
35 |
36 | public CategoryItemRendererState getState() {
37 | return state;
38 | }
39 |
40 | public BarChart setState(CategoryItemRendererState state) {
41 | this.state = state;
42 | return this;
43 | }
44 |
45 | public Rectangle getGraphArea() {
46 | return graphArea;
47 | }
48 |
49 | public BarChart setGraphArea(Rectangle graphArea) {
50 | this.graphArea = graphArea;
51 | return this;
52 | }
53 |
54 | public CategoryPlot getPlot() {
55 | return plot;
56 | }
57 |
58 | public BarChart setPlot(CategoryPlot plot) {
59 | this.plot = plot;
60 | return this;
61 | }
62 |
63 | public CategoryAxis getDomainAxis() {
64 | return domainAxis;
65 | }
66 |
67 | public BarChart setDomainAxis(CategoryAxis domainAxis) {
68 | this.domainAxis = domainAxis;
69 | return this;
70 | }
71 |
72 | public CategoryDataset getDataset() {
73 | return dataset;
74 | }
75 |
76 | public BarChart setDataset(CategoryDataset dataset) {
77 | this.dataset = dataset;
78 | return this;
79 | }
80 |
81 | }
82 |
83 | class CategoryItemRendererState {
84 | public static final CategoryItemRendererState DEFAULT = null;
85 | }
86 |
87 | class CategoryPlot {
88 | public static final CategoryPlot DEFAULT = null;
89 | }
90 |
91 | class CategoryAxis {
92 | public static final CategoryAxis DEFAULT = null;
93 | }
94 |
95 | class ValueAxis {
96 | public static final ValueAxis DEFAULT = null;
97 | }
98 |
99 | class CategoryDataset {
100 | public static final CategoryDataset DEFAULT = null;
101 | }
102 |
103 | @SuppressWarnings("serial")
104 | class BarChartTest extends java.awt.Frame {
105 | ValueAxis myValueAxis = null;
106 | CategoryDataset myDataset = null;
107 | @SuppressWarnings("unused")
108 | // tag::showMyBarChart[]
109 | private void showMyBarChart() {
110 | Graphics g = this.getGraphics();
111 | BarChart b = new BarChart()
112 | .setRangeAxis(myValueAxis)
113 | .setDataset(myDataset)
114 | .draw(g);
115 | }
116 | // end::showMyBarChart[]
117 | }
118 |
--------------------------------------------------------------------------------