Date post: | 22-Jan-2018 |
Category: |
Documents |
Upload: | lloyd-monteiro |
View: | 82 times |
Download: | 2 times |
Approaching Patterns How to Apply
Problem Statement• Cat Simulation
• Walk, run, purr, jump, wag tail
Using OOPS
• Using traditional OOP we take common features of all Cats and put them in a base class. Since the requirement mentioned simulation of different Cats we then create different Cat classes (Siamese, Persian)
• Persian Class will implement its own Display function and so too Siamese.
Change is always a Constant
• The requirements change after a client review meeting and now they want to add functionality that will simulate eating attribute. So all Cats need to eat.
What do we do
• Using power of inheritance, I just have to add a method called Eat() to the base class. Right ?
• What if tomorrow requirement changes to say that they want to add a feature to simulate toy Cats. The client wants to make their simulation kids friendly.
• We know there is a potential problem that a Toy Cat can possibly Purr, Walk, (battery operated) but can it eat?
• So again we can use the power of inheritance and override the functions that we don’t want to use and ask it to not implement anything.
Problems in above design
• Maintenance nightmare
• Readability
• Intuitive
Sharpen What you learnt
• Which of the following are disadvantages of using inheritance to provide Cat type behavior? (Choose all that apply.)
A. Code is duplicated across subclasses.
B. Runtime behavior changes are difficult.
C. We can’t make Cats dance.
D. Hard to gain knowledge of all Cats behaviors.
E. Cats can’t Purr and run at the same time.
F. Changes can unintentionally affect other Cats
Interface – How would it help
• Take what varies and “encapsulate”
• Separate the “parts that change from those that stay the same”
• Create two sets of Interfaces (totally apart from Cat), one for IEat and one for IPurr.
• Each set of concrete classes will hold all the implementations of their respective behavior.
• This is what our new Cats class looks like.
• What we have effectively done is that a Cat will now delegate its Purring and Eating behaviour, instead of using Purring methods defined in the Cat class (or subclasses).
public Class Cats
{
public IEat eat;
public IPurr meow;
.
public void ExecuteEat()
{
eat.Eat();
}
public void ExecutePurr()
{
meow.Purr();
}
}
Public Class Persian : Cats, IEat, IPurr
{
public Persian()
{
eat = new CanEat();
meow = new Whimper();
}
}
Public Class ToyCat : Cats, IEat, IPurr
{
public ToyCat()
{
eat = new CantEat();
}
}
Sample Client code
Public Static Void Main(String[] args….)
{
Cats c = new Persian();
c.ExecutePurr();
c.ExecuteEat();
}
Flexibility and Code Maintenance
• There is still room for flexibility
• We are doing a poor job of initializing the instance variables in a flexible way
• Polymorphism : The PurrBehavior instance variable is an interface type. Dynamically assign a different PurrBehaviorimplementation class at runtime or even from the client without having to alter code.
• Let us make changes below to the Cat class. We are introducing two methods
– SetPurrBehaviour(PurrBehaviour b)
– SetEatBehaviour(EatBehaviour e)
• From the client code now we can dynamically add a new behaviour and without modifying lots of code add extra functionality.
public Class Cats
{
public IEat eat;
public IPurr meow;
.
public void SetPurrBehaviour(IPurr b)
{
meow = b;
}
public void SetEatBehaviour(IEat e)
{
eat = e;
}
}
public class Hiss : IPurr
{
public void Purr()
{
// HISS HISS
}
}
Client Code looks like
• Static void main()
• {
– Cat p = new Persian();
– P. SetPurrBehaviour(new Hiss ());
– P.ExecutePurr();
• }
Welcome to the Strategy Pattern
• Patterns should be applied depending on the need of the situation.
• Apply basic OOPS concepts first then refactor.
• Separate what changes
• Always code to an Interface
• Open for extension and closed for modification
• Favor composition over inheritance.