nov 2005 msc slide 1 first we look at a standard dos based application combining decorator &...
TRANSCRIPT
Nov 2005 MSc Slide
1
First we look at a standard Dos based application
Combining Decorator & Factory Patterns
Nov 2005 MSc Slide
2
class Account{private int balance;public Account(int b) {balance=b;}public Account(Account acc) {balance=acc.balance;}public int read_bal() {return balance;}public void deposit(int amt) {balance +=amt;}public void withdraw(int amt) {balance -=amt;}
}
Combining Decorator & Factory Patterns
public class Ex1{
public static void Main(){ Account a = new Account(20); int choice=1,amt=0; string temp; while(choice!=4){
Console.WriteLine();Console.WriteLine("1: Deposit");Console.WriteLine("2: Withdraw");Console.WriteLine("3: Read Bal");Console.WriteLine("4: Exit");Console.Write("Enter Choice:");
temp=Console.ReadLine(); choice=Convert.ToInt32(temp); :
switch(choice){ case 1: Console.Write("Enter Amount: "); temp=Console.ReadLine(); amt=Convert.ToInt32(temp);
a.deposit(amt); break; case 2: Console.Write("Enter Amount: "); temp=Console.ReadLine();amt=Convert.ToInt32(temp);
a.withdraw(amt); break; case 3: int b=a.read_bal(); Console.WriteLine("Balance="+b); break; }}}}}
Nov 2005 MSc Slide
5
- we introduce trace printouts
public void deposit(int amt){Cosole.WriteLine("deposit()"); balance +=amt;}
During Testing Phase
Nov 2005 MSc Slide
6
class Account{private int balance;public Account(int b) {balance=b;}public Account(Account acc) {balance=acc.balance;}public int read_bal() {Console.WriteLine(”read_bal()"); return balance;}public void deposit(int amt) {Console.WriteLine(”deposit()"); balance +=amt;}public void withdraw(int amt){ Console.WriteLine(”withdraw()"); balance -=amt;}}
Nov 2005 MSc Slide
7
•Must be removed after testing
•What if you need to retest later
•Different test phases my require different types of traces
Unsatisfactory
Alternative Solution using Decorator Pattern
Nov 2005 MSc Slide
9
class Account{private int balance;public Account(int b) {balance=b;}public Account(Account acc) {balance=acc.balance;}public int read_bal() {return balance;}public void deposit(int amt) {balance +=amt;}public void withdraw(int amt) {balance -=amt;}}
Combining Decorator & Factory Patterns
As Before
Nov 2005 MSc Slide
10
class Decorator : Account{protected Account account;public Decorator(Account acc):base(acc){
account=acc;}}
Combining Decorator & Factory Patterns
Nov 2005 MSc Slide
11
class TestAcc : Decorator{
public TestAcc(Account acc):base(acc){}
new public int read_bal(){ print("read_bal()"); return account.read_bal();}
new public void deposit(int amt){print("deposit()"); account.deposit(amt);}
new public void withdraw(int amt){ print("withdraw()"); account.withdraw(amt);}
public void print(String s){ Console.WriteLine(s);}
}
Nov 2005 MSc Slide
12
public class Ex1{
public static void Main(){ TestAcc a = new TestAcc(new Account(20)); int choice=1,amt=0; string temp; while(choice!=4){
Console.WriteLine();Console.WriteLine("1: Deposit");Console.WriteLine("2: Withdraw");Console.WriteLine("3: Read Bal");Console.WriteLine("4: Exit");Console.Write("Enter Choice:");
temp=Console.ReadLine(); choice=Convert.ToInt32(temp); :
public class Ex1{
public static void Main(){ Account a = new Account(20); int choice=1,amt=0; :
After Testing we change back
class SafeAcc : Decorator{
public SafeAcc(Account acc):base(acc); {}
new public int read_bal() {Console.Write("Enter 1 to confirm: "); string temp=Console.ReadLine(); int choice=Convert.ToInt32(temp); if (choice==1) return account.read_bal();
else return 0;}
:
: new public void deposit(int amt){ Console.Write("Enter 1 to confirm: "); string temp=Console.ReadLine(); int choice=Convert.ToInt32(temp);
if (choice==1) account.deposit(amt);}
new public void withdraw(int a) { Console.Write("Enter 1 to confirm: "); string temp=Console.ReadLine(); int choice=Convert.ToInt32(temp);
if (choice==1) account.withdraw(a);}
}
public class Ex1{
public static void Main(){ SafeAcc a = new SafeAcc(new Account(20)); int choice=1,amt=0; : :
After Testing we change back
public class Ex1{
public static void Main(){ Account ac=new Account(20); TestAcc a = new TestAcc(new SafeAcc(null,ac),ac); int choice=1,amt=0; : :
Can combine these
Nov 2005 MSc Slide
22
public class Ex1{
public static void Main(){ Account ac=new Account(20); SafeAcc a = new SafeAcc(new TestAcc(null,ac),ac); int choice=1,amt=0; : :
Can combine these
class TestAcc : Decorator{ private SafeAcc sacc;
public TestAcc(SafeAcc sacc,Account acc):base(acc) {this.sacc=sacc;}
new public int read_bal(){ print("read_bal()");
if (sacc!=null) return sacc.read_bal(); else return account.read_bal();}
new public void deposit(int amt){print("deposit()"); if (sacc!=null) sacc.deposit(amt); else account.deposit(amt);} :
To achieve this we must modify code of decorators
class SafeAcc : Decorator{ private TestAcc tacc;
public SafeAcc(TestAcc tacc,Account acc):base(acc) {this.tacc=tacc;}
new public int read_bal(){ Console.Write("Enter 1 to confirm: "); string temp=Console.ReadLine(); int choice=Convert.ToInt32(temp); if (tacc!=null) return tacc.read_bal(); else return account.read_bal();}:
new public void deposit(int amt){ Console.Write("Enter 1 to confirm: "); string temp=Console.ReadLine(); int choice=Convert.ToInt32(temp); if (tacc!=null) tacc.deposit(amt); else account.deposit(amt);}
new public void withdraw(int amt) { Console.Write("Enter 1 to confirm: "); string temp=Console.ReadLine(); int choice=Convert.ToInt32(temp); if (tacc!=null) tacc.withdraw(amt); else account.withdraw(amt);}}
1. Account a = new Account(bal);
2. SafeAcc a = new SafeAcc(null,new Account(20));
Or alternativeAccount ac=new Account(20);SafeAcc a = new SafeAcc(null,ac);
3. TestAcc a = new TestAcc(null,new Account(20));
4. Account ac=new Account(20); TestAcc a = new TestAcc(new SafeAcc(null,ac),ac);
Can add functionality by adding objectsOptions
Improve by using Factory Pattern
Factory creates an Account object based on data
In the following example base choice on user input
Better solution would be to read value from a configuration file
Could change the value in file after test etc
First We must make some minor changes to introduce Polymorphism
using System;abstract class Decorator :Account{
protected Account account;public Decorator(Account acc):base(acc){
account=acc;}
}class AccInterface{
virtual public int read_bal(){return 0;}virtual public void deposit(int amt){}virtual public void withdraw(int amt){}}
:
using System;abstract class Decorator :Account{
protected Account account;public Decorator(Account acc):base(acc){
account=acc;}
}class AccInterface{
virtual public int read_bal(){return 0;}virtual public void deposit(int amt){}virtual public void withdraw(int amt){}}
:
class Account:AccInterface{private int balance;public Account(int b) {balance=b;}public Account(Account acc) {balance=acc.balance;}override public int read_bal() {return balance;}override public void deposit(int amt) {balance +=amt;}override public void withdraw(int amt) {balance -=amt;}
}
class TestAcc : Decorator{ private SafeAcc sacc;
public TestAcc(SafeAcc sacc,Account acc):base(acc) {this.sacc=sacc;}
override public int read_bal(){ print("read_bal()");
if (sacc!=null) return sacc.read_bal(); else return account.read_bal();}
override public void deposit(int amt){print("deposit()"); if (sacc!=null) sacc.deposit(amt);
else account.deposit(amt);}
etc
public class Ex1{
public static void Main(){ Account ac=new Account(20); AccInterface a = new TestAcc(new SafeAcc(null,ac),ac); int choice=1,amt=0;etc
Now we can use Polymorphism to get the same result
public class Ex1{
public static void Main(){ Console.WriteLine("Enter Account Type:"); Console.WriteLine("1: Normal"); Console.WriteLine("2: Test"); Console.WriteLine("3: Safe");
Console.WriteLine("4: Safe and Test"); Console.Write("Enter Choice:"); string t=Console.ReadLine();
int option=Convert.ToInt32(t); AccInterface a =
AccountFactory.createAccount(20,option); int choice=1,amt=0; (as before)
class AccountFactory{
static public AccInterface createAccount(int bal,int type){Account ac=new Account(bal);if (type==1) return ac;if (type==2) return new TestAcc(null,ac);if (type==3) return new SafeAcc(null,ac);else return new TestAcc(new SafeAcc(null,ac),ac);
} }
public class Ex1{
public static void Main(){ Console.Write("Enter Balance:"); string t=Console.ReadLine();
int bal=Convert.ToInt32(t); AccInterface a = AccountFactory.createAccount(bal);
int choice=1,amt=0; : (as before)
Could also have a Factory Based on a single parameter
class AccountFactory{
static public AccInterface createAccount(int bal){if (bal < 100) return new Account(bal);else return new SafeAcc(null,new Account(bal));
} }
Nov 2005 MSc Slide
40
Exercise1:Given the class
class Counter{private int value;public Counter(int v){value=v;}public Counter(Counter cc){ value=cc.value;}public int read_value(){return value;}public void increment(){value++;}public void decrement(){ value--;}}
Now we want to decorate the Counter (similar to Account Ex)
Nov 2005 MSc Slide
41
(i) class UpperLimit extends Decorator{
same as before except increment will only increment if value <20
otherwise will print out “Too High” Hint:public void increment(){if (counter.read_value()<20)
(ii)class LowerLimit extends Decorator{
same as before except decrement will only decrement if value >0
otherwise will print out “Too Low”
(iii) Want a factory to decide on the of counter See next Dos screen
Nov 2005 MSc Slide
43
Exercise 1(b):
Now Modify the Application so the Factory is based on just an initial counter value read in from the Console:
- Values < 5 will generate a Normal Counter Object- 5-10 inclusive will generate a LowerLimit Object- 11 -15 an UpperLimit Object- Values > 15 will produce one with both an Upper & Lower Limit
Nov 2005 MSc Slide
44
Exercise2:Given the class
class Display{private String name;public Display(String n){name=n;}public Display(Display dd){ name=dd.name;}public void print(){System.out.println("\t"+name);}public void setName(String n){name=n;}}
Will Display a name:
Now we want to decorate the Display (similar to Account Ex)
Nov 2005 MSc Slide
45
Normal Display
Athlone
UpperLine ******************* Athlone
LowerLine Athlone *********************
Upper and Lower Line ******************* Athlone *********************
Nov 2005 MSc Slide
46
(a)class UpperLine extends Decorator{
print a line of ‘*’ before name
(b)class LowerLine extends Decorator{
print a line of ‘*’ after name
(c) Want a factory to decide on the of Display Type See next Dos screen