Each of the letters identifies a specific design principle:
S : Single Responsability Principle (SRP)
O : Open Close Principle (OCP)
L : Liskov Substitution Principle (LSP)
I : Interface Segregation Principle (ISP)
D : Dependency Inversion Principle (DIP)
Like design patterns, design principles are an answer to the software growing complexity and provide key ideas for design quality. I am not about to justify once again why design principles are useful and should be part of every programmer's toolbox. Many object gurus did this better than I would do. I just want to mention one point.
What is interesting with design principles is it is a way to give a name to common design practices. So we can document, we can talk about them. If your software architect comes and tells you, "well, you design is pretty good, there is just a place where I have found an OCP violation that should be fixed". No need for large explaination for this problem. Everybody that is aware of design principles is able to understand what he is talking about.
Following is a simple Banking system that we are going to make evolve step by step for compliance with the 5 SOLID design principles.
Let's start with the Account class. This is the largest one, but the code is simple enough not to require explanations.
1: import java.io.*;
2: import java.util.Date;
3: public class Account
4: {
5: private String name;
6: private double balance = 0.0;
7: PrintWriter print_writer = null;
8: enum StorageType { ASCII_STORAGE, XML_STORAGE };
9: StorageType storage;
10: public Account( String name )
11: {
12: this.name = name;
13: storage = StorageType.ASCII_STORAGE;
14: }
15: public String getName()
16: {
17: return name;
18: }
19: public boolean open()
20: {
21: System.out.println( "Opening account " + name );
22: return true;
23: }
24: public boolean close()
25: {
26: if( balance > 0 )
27: {
28: System.out.println( "Closing account " + name );
29: return true;
30: }
31: else
32: {
33: System.out.println( "Account " + name + " not closed" );
34: return false;
35: }
36: }
37: public void deposit( double amount )
38: {
39: balance += amount;
40: writeRecord( "Deposit", amount );
41: }
42: public void withdraw( double amount )
43: {
44: balance -= amount;
45: writeRecord( "Withdraw", amount );
46: }
47: public double getBalance()
48: {
49: return balance;
50: }
51: public void setStorage( StorageType storage )
52: {
53: this.storage = storage;
54: }
55: private boolean writeRecord( String operation_type, double amount )
56: {
57: if( storage == StorageType.ASCII_STORAGE )
58: {
59: return writeAsciiRecord( operation_type, amount );
60: }
61: else if ( storage == StorageType.XML_STORAGE )
62: {
63: return writeXMLRecord( operation_type, amount );
64: }
65: }
66: private boolean writeAsciiRecord( String operation_type, double amount )
67: {
68: if( print_writer == null )
69: {
70: try {
71: print_writer =
72: new PrintWriter(new FileWriter(name + ".txt"));
73: } catch (IOException ioe) {
74: ioe.printStackTrace();
75: return false;
76: }
77: }
78: Date date = new Date();
79: print_writer.write( date.toString() );
80: print_writer.write( " " );
81: print_writer.write( operation_type ) ;
82: print_writer.write( " " );
83: print_writer.print( amount ) ;
84: print_writer.println() ;
85: print_writer.flush();
86: return true;
87: }
88: private boolean writeXMLRecord( String operation_type, double amount )
89: {
90: // To be written
91: return false;
92: }
93: }
Then we have an Account subclass called SavingAccount:
1: public class SavingAccount extends Account
2: {
3: public SavingAccount( String name )
4: {
5: super( name );
6: }
7: public void creditInterest()
8: {
9: // double interest =
10: // balance += interest;
11: }
12: }
The third class is the Bank class. This class provides basic administration operations as open and close for accounts.
1: import java.util.*;
2: public class Bank
3: {
4: public enum AccountType { CURRENT, SAVING };
5: private Hashtable<String, Account> accounts =
6: new Hashtable<String, Account>();
7: private String name;
8: public Bank( String name )
9: {
10: this.name = name;
11: }
12: public Account openAccount( String name, AccountType type )
13: {
14: Account account = null;
15: if( type == AccountType.CURRENT )
16: account = new Account( name );
17: else if( type == AccountType.SAVING )
18: account = new SavingAccount( name );
19: accounts.put( name, account );
20: account.open();
21: return account;
22: }
23: public boolean closeAccount( Account account )
24: {
25: if( account instanceof SavingAccount )
26: {
27: SavingAccount saving_account = (SavingAccount) account;
28: saving_account.creditInterest();
29: }
30: return account.close();
31: }
32: }
Finally we have a basic Test class so that we can execute the program.
1: public class Test
2: {
3: public static void main( String[] args )
4: {
5: Bank bank = new Bank( "bank" );
6: Account account = bank.openAccount( "my account", Bank.AccountType.CURRENT );
7: if( account == null )
8: return;
9: account.deposit( 100.0 );
10: account.withdraw( 5.0 );
11: double balance = account.getBalance();
12: bank.closeAccount( account );
13: Account saving_account = bank.openAccount( "my saving_account", Bank.AccountType.SAVING );
14: saving_account.deposit( 50.0 );
15: bank.closeAccount( saving_account );
16: }
17: }
In the next post we'll start improving the design by applying the Single Responsability Principle. But you can already have a look to the code and try to think what is going to be done for the first improvement step.
No comments:
Post a Comment