Yes, SpecialTable
can be produced by the same factory (and by the same factory method) that produces Table
. This not a problem, as long as SpecialTable
provides at least the methods guaranteed by the Table
interface (which it does).
This sort of situation makes sense when objects returned from the factory have some guaranteed behaviour/functionality (interface Table
), and some optional stuff (interface SpecialTable
).
So, in order to make use of the optional extra abilities/stuff available on some concrete objects returned by the factory, you have a few choices:
use polymorphism (recommended)
make use of instanceof
(or similar), which can be used to check for interface compliance/exact typing (avoid this if possible!)
Using polymorphism
An example to illustrate: suppose SpecialTable has extra data and an extra widget 'blarg' which appears on the UI representing special tables. Do you really need the code which uses SpecialTable to know that it needs to add 'blarg' to the UI? Or can you just have your external code ask the thing of type Table to add its necessary UI components to some UI container? Then the calling code doesn't care what exact type the thing is -- SpecialTable deals with it, adding the 'blarg' to the container itself. This pattern can be described as the delegate pattern (also sometimes also known as strategy pattern).
Using instanceof (type checking)
Example of instanceof
use:
// Table and SpecialTable are interfaces
Table table = TableFactory.instance().getDefaultTable();
if (table instanceof "SpecialTable") {
SpecialTable specialTable = (SpecialTable)table;
specialTable.specialMethod();
}
table.normalMethod();
Note that when you define your SpecialTable
interface you can declare it as extending the Table interface and then only list the extra methods.
Your factory will be producing concrete objects of either type. So you might have a concrete class called BoringTable
which implements Table
, and a concrete class called ExcitingTable
which implements SpecialTable
.
Beware instanceof!
It's generally better to avoid things like 'instanceof' (or generally speaking, ifs of any kind which depend on what type an object is). You should favour polymorphism instead. By this I mean having multiple different classes, of a common type, enclosing different behaviour in their implementation code.
Ask yourself this: does the class using something of type Table
(which might also be of type SpecialTable
) need to care if it's a special table or not? Can you not hide that distinction in some sort of implementation of the SpecialTable -- have it do something different, something extra, that plain old Table does?
You're question is a bit unclear, but I'll explain what the Strategy pattern is in case you don't have a good understanding.
Strategy allows you to swap part of the functionality of an object dynamically during runtime. This is done by encapsulating the different functionalities in classes that all share a common supertype, and having the object in question (the 'context') own a reference of this supertype.
Than, when the object wants to perform some functionality, it actually delegates to the Strategy object it owns. We can swap the current Strategy object for a different one dynamically via e.g. a public setter method.
Thus swapping the functionality owned by the object.
Note that the Strategy pattern is called that because it allows you to choose different 'strategies' for performing generally the same operation.
For example, in a game you might have a Soldier class. Objects of this class are able to attack bad guys via their attack()
method.
But what if you wanted attack()
to do something different based on the current weapon the soldier holds? For example if currently the weapon is a gun, attack()
will shoot bullets. If it's a knife, attack()
will make the soldier stab people.
A naive way to approach this, would be for Soldier
to hold a String
variable that signifies what the current weapon is. attack()
will than have a long else if
chain to determine the correct logic according to the current weapon. Something like this:
class Soldier{
String weapon;
void setWeapon(String w){ weapon = w; }
void attack(){
if(weapon.equals("gun")) // shoot bullets
else if(weapon.equals("knife")) // slash people
// else if ...
}
}
But this approach is bad and definitely not very Object Oriented. What's so bad about it?
Well, suppose you already had 5 different kinds of weapons, and wanted to add another one to the game. You'd have to go into Soldier and add another else if
to match.
That's not so bad, but what if more classes in your game needed to use weapons? For example, a DefenseTurret could also hold a specific kind of weapon that would govern the way it attack()
s.
That would mean a lot of code duplication between Soldier and DefenseTurret. And again, if you want to add a new weapon - you need to go to both these classes and add logic to them, resulting in classes that keep growing and more and more code duplication. Probably resulting in nasty bugs.
The Strategy pattern is there exactly to provide a more elegant and OO solution to these situations.
With Strategy, each kind of weapon will be implemented in it's own Weapon subclass. Weapon would be an abstract class (or interface) that defines an abstract attack()
method. Each of it's subclasses implements this method differently.
Soldier, instead of holding a String weapon
member, will have a Weapon weapon
member. And it's attack()
method, instead of containing a long else if
chain, will simply delegate to the weapon: weapon.attack()
. Code to clarify:
class Soldier{
// .. stuff omitted
Weapon weapon;
void attack(){
weapon.attack();
}
void setWeapon(Weapon newWeapon){
weapon = newWeapon;
}
}
abstract class Weapon{
public abstract void attack();
}
class Gun extends Weapon{
public void attack{ /* shoot some bullets */ }
}
class Knife extends Weapon{
public void attack{ /* stab some bad guys */ }
}
Much more elegant.
Here's a UML diagram to clarify even more:
And now, what if you wanted to give DefenseTurret
some gun shooting capabilities? Just give it a Weapon
reference and have it delegate to it, like you did with Soldier. You can reuse the code you already wrote without copy-pasting it all the time.
I hope this clarifies what Strategy is. Regarding your question, I couldn't really understand it, but it seems to me what you're doing doesn't clarify as a Strategy implementation since your swapping data (i.e. with a simple setter that sets a String value), but not swapping functionality and logic.
I'll be happy to help if you explain more clearly what your problem is.
Best Answer
First thing that strikes me as a problem is using exceptions for validation result. Don't use exceptions for application logic. Just return an enum value. I would assume there are not many ways validation can end up.
Next thing I would question is using of two strategies. What would happen if you used SMS generator with Email validator? To me, it seems there should be just one strategy with both
generate
andvalidate
methods. As for "merging the two violates SRP", I would actually say having them separate violates SRP. SRP is about cohesion. And cohesion works both ways. It separates non-cohesive code and joins cohesive code that was split. Ask yourself "If I changed how Email one-time-password policy worked, would I change only generator or validator or would I have to change both?". I'm quite sure you would need to change both, meaning generation and validation are cohesive parts. If you are worried about putting email sending into the strategy implementation, then that should be strategy's concern.OTPContext
doesn't need to be bothered by that. It doesn't need to know generation uses some special logic, that is not relevant to validation.Last nitpick is that I would prefer if strategy was set to
OTPContext
in a constructor instead of getters/setters. What would happen if you changed the validator strategy after code was generated? You should keep things read-only unless there is explicit requirement for things to change.