List of classes versus class of lists - oop

I have an OOP design question.
Let's assume that I have a class that contains several numerical scalar properties like maximum, minimum, frequency etc. Since data are flowing in continuously I eventually end up with a list of such class instances. To obtain, say, the global minimum I loop over all classes in the list to find it.
Alternatively, I could instantiate one class (possibly a singleton) that contains lists instead of scalars for each property, and function members that loop over the lists. This approach however seems to generate code that looks more like procedural than object oriented programming.
The question is: What criterions define which approach to choose? If efficiency is important, should I choose one class that contains lists for each properties? If readability is key, should I choose a list of classes?
Thanks for suggestions.

Basically you're askyng if it's more preferable to have an "Array of Structures (AoS)" or "Structure of Arrays (SoA)"
The answer depends on what you need to do with this data. If you want to write a more readable code than go for an Array of Structures, if you want to use SSE or CUDA to optimize your computation-heavy code then go for a Structure of Arrays.
If you search in literature the terms "Array of Structures (AoS)" and "Structure of Arrays (SoA)" you will find many in depth dissertations on this topic, i link just some discussions here:
Structure of arrays and array of structures - performance difference
http://hectorgon.blogspot.it/2006/08/array-of-structures-vs-structure-of.html
http://people.maths.ox.ac.uk/~gilesm/hpc/NVIDIA/NVIDIA_CUDA_Tutorial_No_NDA_Apr08.pdf
http://en.wikipedia.org/wiki/Stream_processing

You were asking for decision criteria. Let me recommend one:
You should think about what constitutes a data point in your application. Let's assume you are measuring values, and one data point consists of several numerical properties. Then you would certainly want a list of classes, where the class represents all of the properties that go together (what I called 'data point' for lack of a better term).
If you must perform some aggregation of these 'data points', such as finding a global minimum over a longer time period, I would suggest designing an extra component for this. So you'd end up with a data gathering component which consists mainly of a 'list of classes', and an aggregation component which may utilize different data structures, but processes parts of your 'list of classes' (say, the part over which the global minimum is to be found).

Basically, OOP is not a solution to every question in programming, sometimes you have to see beyond this,below this. The thing is you have to concentrate on the problem. Efficiency should be more preferable. But if your code is taking too much time to load or you can say its time complexity is too much high then again you'll have trouble. You have to keep to keep both ends in hands. What i'll prefer is the list of classes not the class of list. But different people have different point of views and so we should respect them. Why i am chosing list of classes because,i'll have each object with the respected data, say , i have one object with higher frequency,one with lower,one with a medium,it will be easier to manage all that,plus not much time will be taken. i think in both cases it will be O(n) where n is the number of elements or classes in my case.

In your case, list of data
struct Statistic{
int max;
int min;
std::vector<int> points;
int average;
};
int main(){
std::vector<Statistic> stats;
return 0;
}

You could also store the values and the statistics together in one class and do the calculations on the fly when adding a new value (example in Java):
public class YourClass {
private List<Integer> values = new ArrayList<Integer>();
private long sum = 0;
private int minimum = Integer.MAX_VALUE;
private int maximum = Integer.MIN_VALUE;
// add more stuff you need
public synchronized void add(Integer value) {
values.add(value);
sum += value;
if (value < minimum) {
minimum = value;
}
if (value > maximum) {
maximum = value;
}
}
public List<Integer> getValues() {
return Collections.unmodifiableList(values);
}
public long getSum() {
return sum;
}
public long getAvg() {
return values.isEmpty() ? 0 : sum / values.size();
}
public int getMaximum() {
return maximum;
}
public int getMinimum() {
return minimum;
}
}

Related

Object Oriented Programming: Subclasses or Enum

I am making a simple turn-based farming simulator game where players make choices whether to buy land or crops and have turn-count based growing. Different crops grow for different times, and have different purchase prices and sale values. Objective is to be the first to reach a dollar amount.
My question is how to develop these crops programmatically. I currently have each crop variation as a subclass of a Crop, however, this leads to a lot of redundancy (mostly different field/attribute values, or image paths). Since these objects are very similar save for some values, should they be subclasses, or would it be better practice to make one class Crop with an Enum of type and use logic to determine the values it should have?
Superclass Crop
subclass Wheat
subclass Corn
subclass Barley
Or
Crop.Type = CropType.Wheat
if(this.Type == CropType.Wheat) { return StockMarket.Wheat_Sell_Value; }
else if(this.Type == CropType.Corn) { return StockMarket.Corn_Sell_Value; }
If you make a single crop class it risks becoming very large and unwieldly, especially if you want to add a new crop type you'll have to update the 100's of if statements littered through your code (e.g. if(this.Type == CropType.Wheat) { return StockMarket.Wheat_Sell_Value; }).
To echo #oswin's answer, use inheritance sparingly. You are probably ok using a base-class with a few "dumb" properties, but be especially careful when adding anything that implements "behaviour" or complexity, like methods and logic; i.e. anything that acts on CropType within Crop is probably a bad idea.
One simple approach is if crop types all have the same properties, but just different values; and so crop instances just get acted on by processes within the game, see below. (Note: If crops have different properties then I would probably use interfaces to handle that because they are more forgiving when you need to make changes).
// Crop Types - could he held in a database or config file, so easy to add new types.
// Water, light, heat are required to grow and influence how crops grow.
// Energy - how much energy you get from eating the crop.
Name:Barley, growthRate:1.3, water:1.3, light:1.9, heat:1.3, energy:1.4
Name:Corn, growthRate:1.2, water:1.2, light:1.6, heat:1.2, energy:1.5
Name:Rice, growthRate:1.9, water:1.5, light:1.0, heat:1.4, energy:1.8
The crop type values help drive logic later on. You also (I assume) need crop instance:
class CropInstance
{
public CropType Crop { get; set; }
public double Size { get; set; }
public double Health { get; }
}
Then you simply have other parts of your program that act on instances of Crop, e.g:
void ApplyWeatherForTurn(CropInstance crop, Weather weather)
{
// Logic that applies weather to a crop for the turn.
// E.g. might under or over supply the amount of water, light, heat
// depending on the type of crop, resulting in 'x' value, which might
// increase of decrease the health of the crop instance.
double x = crop.WaterRequired - weather.RainFall;
// ...
crop.Health = x;
}
double CurrentValue(CropInstance crop)
{
return crop.Size * crop.Health * crop.Crop.Energy;
}
Note you can still add logic that does different things to different crops, but based on their values, not their types:
double CropThieves(CropInstance crop)
{
if(crop.health > 2.0 & crop.Crop.Energy > 2.0)
{
// Thieves steal % of crop.
crop.Size = crop.Size * 0.9;
}
}
Update - Interfaces:
I was thinking about this some more. The assumption with code like double CurrentValue(CropInstance crop) is that it assumes you only deal in crop instances. If you were to add other types like Livestock that sort of code could get cumbersome.
E.g. If you know for certain that you'll only ever have crops then the approach is fine. If you decide to add another type later, it will be manageable, if you become wildly popular and decide to add 20 new types you'll want to do a re-write / re-architecture because it won't scale well from a maintenance perspective.
This is where interfaces come in, imagine you will eventually have many different types including Crop (as above) and Livestock - note it's properties aren't the same:
// growthRate - how effectively an animal grows.
// bredRate - how effectively the animals bred.
Name:Sheep, growthRate:2.1, water:1.9, food:2.0, energy:4.6, bredRate:1.7
Name:Cows, growthRate:1.4, water:3.2, food:5.1, energy:8.1, breedRate:1.1
class HerdInstance
{
public HerdType Herd { get; set; }
public int Population { get; set; }
public double Health { get; }
}
So how would interfaces come to the rescue? Crop and herd specific logic is located in the relevant instance code:
// Allows items to be valued
interface IFinancialValue
{
double CurrentValue();
}
class CropInstance : IFinancialValue
{
...
public double CurrentValue()
{
return this.Size * this.Health * this.Crop.Energy;
}
}
class HerdInstance : IFinancialValue
{
...
public double CurrentValue()
{
return this.Population * this.Health * this.Herd.Energy - this.Herd.Food;
}
}
You can then do things with objects that implement IFinancialValue:
public string NetWorth()
{
List<IFinancialValue> list = new List<IFinancialValue>();
list.AddRange(Crops);
list.AddRange(Herds);
double total = 0.0;
for(int i = 0; i < list.Count; i++)
{
total = total + list[i].CurrentValue();
}
return string.Format("Your total net worth is ${0} from {1} sellable assets", total, list.Count);
}
You might recall that above I said:
...but be especially careful when adding anything that implements
"behaviour" or complexity, like methods and logic; i.e. anything that
acts on CropType within Crop is probably a bad idea.
...which seems to contradict the code just above. The difference is that if you have one class that has everything in it you won't be able to flex, where as in the approach above I have assumed that I can add as many different game-asset types as I like by using the [x]Type and [x]Instance architecture.
The answer depends on the difference in functionality between the crop types. The general rule is to avoid unnecessary complexity where possible and inheritance should be used sparingly because it introduces hard dependencies.
So if all crops are functionally similar and only differ by their attribute values then you would want to use a single class for crop, but if your game logic demands the crop types to behave very differently and/or carry very different sets of data, then you may want to consider creating separate structures.
If inheritance would be the best choice (in case you need separate structures) cannot be answered without knowing the exact details of your game world either. Some alternatives you could consider are:
interfaces (or another type of mix-in), which allows you to re-use behavior or data across multiple types, e.g. if crops can be harvested, maybe forests can be harvested as well.
structs (or data-classes), which only define the data structure and not the behavior. This is generally more efficient and forces you to do a simpler design with less abstractions.
a functional programming approach where the crops only exist as primitives being passed around functions. This has all the benefits of functional programming, such as no side effects, less bugs, easier to write tests, easier concurrency designs which can help your game scale larger.

Limiting Parameters

Probably going to get shot down for this, but I have an issue with my parameters.
Say I need to store a race (Which I do)
During planning, I realized I needed to store things like:
Terrain of the race
location of the race
time the race starts
time admission ends.
Name of the Race
Types of member permitted to join
etc
In short, it's a ton of underivable data that can't really come from elsewere
and all in all, I have like, 22 parrameters for my JuniorRace object, and like 26 Parameters for my SeniorRace object, I've already coded it but it's messy and I don't like my work.
This wouldn't be a massive problem, and it actually won't be a problem AT ALL for the users since they won't see the business model, just the view model, but it is for me having to constantly comment these same parameters multiple times.
What is the best way I can stop using so many parameters every time I make a constructor, and every time I create a new object instance?
do I just try to use less and store data elsewhere, if so, where?
use more classes like Person would have Address and Details?
I'm really stumped here, will post my code, but yeah, it's a ton of parameters pretty much everywhere -- I'm not a very experienced OO programmer.
You could store all the parameters as a map and just pass in the map, something like:
Map myParams = new HashMap<String,Object>();
myParams.add("Terrain","terrible");
myParams.add("Location","Bobs back yard");
myParams.add("Length (yards)", 100);
myParams.add("Hazards", new String[] {"Bob's cat","The old tire","the fence"});
Then you could calll your routine like this:
SaveRaceCourse(myParams);
Maps and suchlike are great for passing around data.
As I can't see all 22 parameters this is a guess but most probably a correct one.
Are some of those 22 parameter related. If so group the related ones in another class and make SeniorRace a composition of all these classes.
For example: location and terrain seem related, admission period and allowed member types seems related to admission (maybe a fee is part of it too).
This way you will end up with a limited set of objects to pass, all related info lives together and evolve together.
Break it down by encapsulating similar properties in objects. It's called decomposition.
For example, your Race can accept a TimeCard encapsulating all the timing details, a Location which has the terrain and what not (maybe directions), an object encapsulating the requirements, ect...
class RaceTimeCard {
private final Timestamp admissionStart;
private final Timestamp admissionEnd;
private final Timestamp raceStart;
private Timestamp raceEnd;
public RaceTimeCard(Timestamp admissionStart, Timestamp admissionEnd, Timestamp raceStart) {
//init final fields
}
public void endRace() {
//clock the time that the race ended
}
}
class RaceLocation {
private final Terrain terrain;
private final Directions directions;
private final GPSCoordinates coordinates;
public RaceLocation(Terrain terrain, Directions directions, GPSCoordinates coordinates) {
//init final fields
}
}
class Race {
private RaceTimeCard timeCard;
private RaceLocation location;
public Race(RaceTimeCard timeCard, RaceLocation) {
//init fields
}
}
If you'd like, you could subclass Location and TimeCard to create specific instances:
final class Mountains extends RaceLocation {
public Mountains() {
super(Terrain.ROCKY, new Directions(...), new GPSCoordinates(...));
}
}
final class EarlyBirdTimeCard extends RaceTimeCard {
public EarlyBirdTimeCard() {
//specify super constructor with params
}
}
Now instantiating your Race object is as simple as:
RaceTimeCard timeCard = new EarlyBirdTimeCard();
RaceLocation location = new Mountains();
...
Race race = new Race(timeCard, location, ...);
If it's still too long, you can probably decompose more. The way I see it, you could have a RaceDetails object containing all the (already decomposed) details, then pass that to Race. Make sure to profile your application, make sure the overhead from object creation doesn't get too bad.

Is it bad OOP practice to subclass MANY classes from a base class?

I'm relatively new to this site so if I am doing something wrong when it comes to posting questions and whatnot please let me know so I can fix it for next time.
I'm curious as to whether or not it is bad OOP practice to subclass multiple classes from a single base class. That probably doesn't quite make sense so I'm going to elaborate a little bit.
Say for instance you are designing a game and you have several different monsters you might come across. The approach I would take is to have a base abstract class for just a general monster object and then subclass all of the specific types of monsters from the base class using a new class.
One of my instructors told me that you shouldn't rely on inheritance in this case because the number of monsters will continue to grow and grow and the number of classes will increase to a point where it is hard to keep track of all of them and thus yo will have to recompile the program with every new class added in the future.
I don't understand why (or even if) that's a bad thing. If anybody could help me understand where my professor is coming from that would be much appreciated.
Thanks!
If monsters are very similar, in that the only differences are (for example) their name, how much damage they impart, what color they are, etc., then these differences which can be reflected in a field (in values), may make sub-classing unnecessary.
If, however, you have monsters that are fundamentally different from others, such that it is necessary to have very different methods and logic, and more specifically, differences that cannot be reflected in fields, then a sub-class SpecialMonster may be necessary.
But again, even SpecialMonster may not need to be sub-classed by individual monster types, as it's fields may be enough to distinguish between them.
While it's legal to have a million sub-classes of specific monster types, you don't want to take care of all that duplicate code when it could simply be expressed in the fields of new Monster instances, such as
new Monster("Goob", WakeTime.NOCTURNAL, 35, new Weapon[]{sword, hammer, knittingNeedle});
new Monster("Mister Mxyzptlk", WakeTime.ANYTIME, 71, new Weapon[]{sword, mindMeld, cardboardCutter});
There is an alternative, where you do have a lot of classes, but you don't impose them onto your users, and you don't clutter up your API/JavaDoc with them. If your Monster happens to be an abstract class
public abstract class Monster {
private final String name;
...
public Monster(String name, int default_damage, WakeTime wake_time, Weapon[] weapons) {
this.name = name;
...
}
public String getName() {
return name;
}
...
public abstract int getDamage(int hit_strength);
}
Then you could have a Monster convenience creator like this:
/**
<P>Convenience functions for creating new monsters of a specific type.</P>
**/
public class NewMonsterOfType {
private NewMonsterOfType() {
throw new IllegalStateException("Do not instantiate.");
}
/**
<P>Creates a new monster that is nocturnal, has 35-default-damage, and whose weapens are: sword, hammer, knittingNeedle.</P>
**/
public static final GOOB = new GoobMonster();
/**
<P>Creates a new monster that can be awake at any time, has 71-default-damage, and whose weapens are: sword, mindMeld, cardboardCutter.</P>
**/
public static final MISTER_MXYZPTLK = new MisterMxyzptlkMonster();
}
class GoobMonster extends Monster {
public GoobMonster() {
super("Goob", WakeTime.NOCTURNAL, 35, new Weapon[]{sword, hammer, knittingNeedle});
}
public int getDamage(int hit_strength) {
return (hit_strength < 70) ? getDefaultDamage() : (getDefaultDamage() * 2);
}
}
class MisterMxyzptlkMonster extends Monster {
public GoobMonster() {
super("Mister Mxyzptlk", WakeTime.ANYTIME, 71, new Weapon[]{sword, mindMeld, cardboardCutter});
}
public int getDamage(int hit_strength) {
return (hit_strength < 160) ? getDefaultDamage() + 10 : (getDefaultDamage() * 3);
}
}
In order for these private (actually package-protected) classes to not show up in you JavaDoc, you need to set its access to something either protected or public.
Inheritance is quite natural in your scenario as all the specific monsters ARE base monsters as well :). I'd actually use inheritance a lot here, since probably specific monsters do have specific behaviour that would have to be overriden. MonsterA might move by crawling while MonsterB might move by flying. The base AMonster would have an abstract Move() method , implemented by those sub types.
This isn't a final answer, it really much depends on the game needs, however, in simplified form, inheritance makes sense here. The number of monster types might continue to grow, but really, are they all the same? The monster design is just based on grouping together some predefined data/behaviour? The game is quite trivial then...
I really get the impression your instructor doesn't code games for a living (me neither, although I did make a game some time ago), but his explanation why you shouldn't use inheritance is way too simplified. The number of defined classes is never an issue in an app, the more the better IF the Single Responsibility Principle is respected.
About you have to recompile your app.... yeah, when you fix a bug you have to recompile it too. IMO, the reasons he gave to you aren't valid for this scenario. He needs to come up with much better arguments.
In the mean time, go for inheritance.
Theoretical question needs theoretical answer :).
It is not just bad, it is pointless. You should have a LIMITED number of "base" classes that inherits from other classes, and those classes should be composed from other classes (vide favour composition versus inheritance).
So as complexity grows the number of classes that base classes are composed from should grows. Not number of base classes itself.
It is like in the industry. If you see machines for instance, they are really composed from large quantity of small parts, and some of those small parts are the same in different machines. When yo designing new machine you do not order new unique "base" part for it just to have a name for your new machine. You use parts existing on a market and you designing some new parts (not "base") only if you cannot find existing counterparts...

Using design patterns to model a subscription system

Here briefly are the business requirements.
I have an entity called PricingSchedule that represents a "subscription" to a system. We use the term "Pricing Schedule", not "subscription" in our team's ubiquitous language, but in theory, a subscription is the same thing.
What determines the Price of the PricingSchedule is the combination of two things:
1. the "duration" of the PricingSchedule (aka, how long is your subscription... 1 year, 2 years, etc...
2. how many Styles (another entity) you want to include in your PricingSchedule. You have two options for how to include Styles; 1. pay per Style, 2. pay for all Styles
Number two is a newly added requirement. Before, it was primarily the PricingSchedule's Duration that determined the Price.
My problem is this... the Price of a PricingSchedule doesn't mean anything when either the Duration, or StylePricingType is applied by itself. I can only get the final Price when they're combined together; aka, 2 years duration with 5 styles.
We have four possible pre-determined durations, ranging from a couple of days, to a 3 or 4 years.
We have two possible ways to bill Style selection; 1. per Style or 2. all Styles. These two things combined then determined the overall Price.
I started thinking the Strategy design pattern could help me here, aka;
public interface IDurationPricingStrategy
public decimal GetDurationPriceFor(PricingSchedule)
public interface IStylePricingStrategy
public decimal GetStylePriceFor(PricingSchedule)
This is a good way to separate things that probably will change going forward, but herein lies the rub; I can't implement one Strategy without knowing the other Strategy's "conditionals."
For example, for the IStylePricingStrategy, I implement the unlimited style pricing option like so:
public class UnlimitedStylePricingStrategy : IStylePricingStrategy
{
public decimal GetStylePriceFor(PricingSchedule)
{
if (PricingSchedule.Duration.Type == DurationType.OneYear)
{
return decimal x;
}
if (PricingSchedule.Duration.Type == DurationType.TwoYears)
{
return decimal x;
}
}
}
if I take this approach, that means if and when I have to add or change a Duration pricing type, then I have to change my StyleStrategy implementation class, which breaks SRP, and basically puts me back to square one.
It's easy if there is only one "thing" that determines the Price for the PricingSchedule, but when I have two things like this, that's where I'm hitting a wall.
Is there another pattern I can use, or somehow use the Strategy pattern differently? I feel that the problem still pulls me towards Strategy, but I'm not sure how to incorporate two Strategies instead of one.
Thanks so much!
Mike
I think one way might be to create an interface for the duration:
public interface IDuration
{
int GetDuration();
decimal CalculatePrice(object whatever); // int something, or whatever.
}
The have your schedule class use it:
public class PricingSchedule
{
public IDuration Duration { get; set; }
}
Then your payment style classes could use the duration like so:
public class UnlimitedStylePricingStyle : PricingStyle
{
public override void GetStylePriceFor(PricingSchedule schedule)
{
int duration = schedule.Duration.GetDuration();
//.....
}
}
The tricky one is days, I'm not sure how you would deal with that, but I would think that using an interface is your best bet here. If you need to add a new duration, you simply implement the interface IDuration.
You could then calculate the price by something like:
public override void GetStylePriceFor(PricingSchedule schedule)
{
int duration = schedule.Duration.GetDuration();
int temp = 34;
decimal result = schedule.Duration.CalculatePrice(temp);
}
Hope this give you a rough idea.

avoiding if statements

I was thinking about object oriented design today, and I was wondering if you should avoid if statements. My thought is that in any case where you require an if statement you can simply create two objects that implement the same method. The two method implementations would simply be the two possible branches of the original if statement.
I realize that this seems extreme, but it seems as though you could try and argue it to some extent. Any thoughts on this?
EDIT
Wow that didn't take long. I suppose this is way too extreme. Is it possible to say though, that under OOP you should expect way less if statements?
SECOND EDIT
What about this: An object that determines its method implementation based on its attributes. That is to say you can implement someMethod() in two ways and specify some restrictions. At any point an object will route to the correct method implementation based on its properties. So in the case of if(x > 5) just have two methods that rely on the x attribute
I can tell you one thing. No matter what people say, thinking about simplifying and eliminating unnecessary branching is a sign of you maturing as a software developer. There are many reasons why branching is bad, testing, maintenance, higher rate of bugs and so on. This is one of the things I look for when interviewing people and is an excellent indicator how mature they are as a developer. I would encourage you to keep experimenting, simplifying your code and design by using less conditions. When I did this switch I found much less time debugging my code, it simply worked, then when I had to change something, changes were super easy to make since most of the code was sequential. Again I would encourage you 100% to keep doing what you are doing no matter what other people say. Keep in mind most developers are working and thinking at much lower level and just follow the rules. So good job bringing this up.
Explain how to implement the following without an if statement or ternary logic:
if ( x < 5 ) {
x = 0
} else {
print x;
}
Yes its true that often complex conditionals can be simplified with polymorphishm. But its not useful all the time. Go read Fowler's Refactoring book to get an idea of when.
http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
Completely eliminating if statements is not realistic and I don't think that is what Ori is suggesting. But they can often be replaced using polymorphism. (And so can many switch statements).
Francesco Cirillo started the Anti-If Campaign to raise awareness of this issue. He says:
Knowing how to use objects lets developers eliminate IFs based on type, those that most often compromise software's flexibility and ability to evolve.
You or your team can also join the campaign.
One of my teacher used to say that. I tend to think that people being so dogmatic about that kind of thing usually don't program for a living.
Avoiding If Statement: There are many ways to do, one of them is below:
int i=0;
if(i==1)
{
//Statement1
}
if(i==2)
{
//Statement2
}
if(i==3)
{
//Statement3
}
if(i==4)
{
//Statement4
}
Using Dictionary and delegate:
delegate void GetStatement ();
Dictionary<int,GetStatement > valuesDic=new Dictionary<int,GetStatement >();
void GetStatement1()
{
//Statement1
}
void GetStatement2()
{
//Statement2
}
void GetStatement3()
{
//Statement3
}
void GetStatement4()
{
//Statement4
}
void LoadValues()
{
valuesDic.Add(1,GetStatement1);
valuesDic.Add(2,GetStatement2);
valuesDic.Add(3,GetStatement3);
valuesDic.Add(4,GetStatement4);
}
Replacing If Statement:
int i=0;
valuesDic[i].Invoke();
Have a look at the Anti-If Campaign The idea is not to replace every single if in your application with the Strategy or State Pattern. The idea is that when you have complex branching logic especially based on something like an enumeration, you should look to refactoring to the Strategy Pattern.
And that case you can remove the if all together by using a Factory. Here is a relatively straightforward example. Of course as I said in a real case, the logic in your strategies would be a bit more complex than just printing out "I'm Active".
public enum WorkflowState
{
Ready,
Active,
Complete
}
public interface IWorkflowStrategy
{
void Execute();
}
public class ActiveWorkflowStrategy:IWorkflowStrategy
{
public void Execute()
{
Console.WriteLine("The Workflow is Active");
}
}
public class ReadyWorkflowStrategy:IWorkflowStrategy
{
public void Execute()
{
Console.WriteLine("The Workflow is Ready");
}
}
public class CompleteWorkflowStrategy:IWorkflowStrategy
{
public void Execute()
{
Console.WriteLine("The Workflow is Complete");
}
}
public class WorkflowStrategyFactory
{
private static Dictionary<WorkflowState, IWorkflowStrategy> _Strategies=
new Dictionary<WorkflowState, IWorkflowStrategy>();
public WorkflowStrategyFactory()
{
_Strategies[WorkflowState.Ready]=new ReadyWorkflowStrategy();
_Strategies[WorkflowState.Active]= new ActiveWorkflowStrategy();
_Strategies[WorkflowState.Complete] = new CompleteWorkflowStrategy();
}
public IWorkflowStrategy GetStrategy(WorkflowState state)
{
return _Strategies[state];
}
}
public class Workflow
{
public Workflow(WorkflowState state)
{
CurrentState = state;
}
public WorkflowState CurrentState { get; set; }
}
public class WorkflowEngine
{
static void Main(string[] args)
{
var factory = new WorkflowStrategyFactory();
var workflows =
new List<Workflow>
{
new Workflow(WorkflowState.Active),
new Workflow(WorkflowState.Complete),
new Workflow(WorkflowState.Ready)
};
foreach (var workflow in workflows)
{
factory.GetStrategy(workflow.CurrentState).
Execute();
}
}
}
In some ways this can be a good idea. Swiching on a type field inside an object is usually a bad idea when you can use virtual functtions instead. But the virtual function mechanism is in no way intended to replace the if() test in general.
How do you decide which object's method to use without an if statement?
It depends on what the original statement is comparing. My rule of thumb is that if it's a switch or if testing equality against an enumeration, then that's a good candidate for a separate method. However, switch and if statements are used for many, many other kinds of tests -- there's no good way to replace the relational operators (<, >, <=, >=) with specialized methods, and some kinds of enumerated tests work much better with standard statements.
So you should only replace ifs if they look like this:
if (obj.Name == "foo" || obj.Name == "bar") { obj.DoSomething(); }
else if (obj.Name == "baz") { obj.DoSomethingElse(); }
else { obj.DoDefault(); }
In answer to ifTrue's question:
Well, if you have open classes and a sufficiently strong dependent type system, it's easy, if a bit silly. Informally and in no particular language:
class Nat {
def cond = {
print this;
return this;
}
}
class NatLessThan<5:Nat> { // subclass of Nat
override cond = {
return 0;
}
}
x = x.cond();
(continued...)
Or, with no open classes but assuming multiple dispatch and anonymous classes:
class MyCondFunctor {
function branch(Nat n) {
print n;
return n;
}
function branch(n:NatLessThan<5:Nat>) {
return 0;
}
}
x = new MyCondFunctor.branch(x);
Or, as before but with anonymous classes:
x = new {
function branch(Nat n) {
print n;
return n;
}
function branch(n:NatLessThan<5:Nat>) {
return 0;
}
}.branch(x);
You'd have a much easier time if you refactored that logic, of course. Remember that there exist fully Turing-complete type systems.
Assume we have conditional values.
public void testMe(int i){
if(i=1){
somevalue=value1;
}
if(i=2){
somevalue=value2;
}
if(i=3){
somevalue=value3;
}
}
//**$$$$$you can replace the boring IF blocks with Map.$$$$$**
// ============================================================
Same method would look like this:
--------------------------------
public void testMe(int i){
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1,value1);
map.put(2,value2);
map.put(3,value3);
}
This will avoid the complicated if conditions.
You can use simliar solution when using factory patterns for loading classes.
public void loadAnimalsKingdom(String animalKingdomType)
if(animalKingdomType="bird"){
Bird b = new Bird();
}
if(animalKingdomType="animal"){
Animal a= new Animal();
}
if(animalKingdomType="reptile"){
Reptile r= new Reptile();
}
}
Now using map :
public void loadAnimalsKingdom(String animalKingdomType)
{
Map <String,String> map = new HashMap<String,String>();
map.put("bird","com.animalworld.Bird.Class");
map.put("animal","com.animalworld.Animal.Class");
map.put("reptile","com.animalworld.Reptile.Class");
map.get(animalKingdomType);
***Use class loader to load the classes on demand once you extract the required class from the map.***
}
Like the solution? Give thumbs-up. - Vv
Creating a whole new class for an else, while technically doable, would likely result in code that is hard to read, maintain, or even prove correct.
That's an interesting idea. I think that you could theoretically do this, but it would be an enormous pain in a language not specifically designed to support it. I certainly don't see any reason to.
I think what he is saying or what he means to say is that he thinks it is best to avoid over-abuse of "tagging" and adding custom functionality to a class by several if statements when it better makes sense to subclass or rethink the object hierarchy.
It is quite extreme. Doing what you are suggesting would cause a lot of needless code duplication, unless the entire function was completely different, based on a single surrounding if; and if so, that if should probably have been on the other side of the method invocation.
If-statements certainly have their place in object-orient design.
Surely some form of comparison needs to be made regardless of what you do? In the end ... sure you can avoid if statements but you'd be producing code that is IDENTICAL to the code using an if statement.
Someone correct me if im wrong but I can't think of a time where you could get any win form doing this.
I think applying that argument to the idea of every if statement is pretty extreme, but some languages give you the ability to apply that idea in certain scenarios.
Here's a sample Python implementation I wrote in the past for a fixed-sized deque (double-ended queue). Instead of creating a "remove" method and having if statements inside it to see if the list is full or not, you just create two methods and reassign them to the "remove" function as needed.
The following example only lists the "remove" method, but obviously there are "append" methods and the like also.
class StaticDeque(collections.deque):
def __init__(self, maxSize):
collections.deque.__init__(self)
self._maxSize = int(maxSize)
self._setNotFull()
def _setFull(self):
self._full = True
self.remove = self._full_remove
def _setNotFull(self):
self._full = False
self.remove = self._not_full_remove
def _not_full_remove(self,value):
collections.deque.remove(self,value)
def _full_remove(self,value):
collections.deque.remove(self,value)
if len(self) != self._maxSize and self._full:
self._setNotFull()
In most cases it's not that useful of an idea, but sometimes it can be helpful.
I will say the answer is vaguely yes-ish. Especially when the language allows some heavy duty functional programming (ie C#, F#, OCaml).
A component that contains 2 if statements strongly couples two business rules so break it up.
Take that as a very general rule of thumb but I would agree. If you have a bunch of if statements, maybe you should think about another approach.
If-statements are pretty core to programming so, in short, you cannot sensibly avoid them.
However, a key goal in OOP--in fact, one of the "pillars"--is encapsulation. The old "encapsulate what varies" rule helps you remove those troublesome if and case statements where you are trying to account for every option in your object. A better solution to dealing with branches, special cases, etc. is to use something like the "Factory" design pattern (Abstract Factory or Factory Method--depending on needs, of course).
For example, rather than having your main code loop check which OS your using with if statements then branch to create GUI windows with different options for each OS, your main code would create an object from the factory, which use the OS to determine which OS-specific concrete object to make. In doing this you are taking the variations (and the long if-then-else clauses) out of your main code loop and letting the child objects handle it--so the next time you need to make a change such as supporting a new OS, you merely add a new class from the factory interface.
I've been following the anti-if talk lately and it does sound like extreme / hyperbolic rhetoric to me. However I think there is truth in this statement: often the logic of an if statement can be more appropriately implemented via polymorphism. I think it is good to keep that in mind every time you right an if statement. That being said, I think the if statement is still a core logic structure, and it should not be feared or avoided as a tenet.
My two bits here of what I understand of the Object Oriented approach -
First, what objects in a program should be intuitive. That is, I should not try to create a 'Arithmatic' class to provide mathematical functions. This is an abuse of OOD.
Second and this is a very strong opinion of mine. It should not be called Object Oriented design but Object and Method Oriented design! If the method names of the objects are themselves not intuitive then inherited objects might end up reimplementing the methods already available.
Object Oriented approach, according to me, is not a replacement for the Procedural approach. Rather it is mainly for two main reasons for the creators of the language -
Better capability of scoping of variables.
Better capability of garbage collection rather than having too many global variables.
I agree with Vance that the IF is not good, because it increases the conditional complexity and should be avoided as possible.
Polymorphism is a totally viable solution at condition it's used to make sense and not to "Avoid If".
A side note that does not fit to your OOP requirements but the Data Oriented approach also tends to avoid the branching.
You must understand what (x > 5) really mean. Assuming that x represents a number, then it basically "classifies" all numbers greater than five. So the code would look like this in a language with python syntax:
class Number(Object):
# ... Number implementation code ... #
def doSomething():
self = 0
return self
def doSomethingElse():
pass
class GreaterThan5(Number):
def doSomething():
print "I am " + self
def doSomethingElse():
print "I like turtles!"
Then we could run code like the following:
>>> type(3)
<class Number>
>>> type(3+3)
<class GreaterThan5>
>>> 3.doSomething()
0
>>> (3 + 3).doSomething()
I am 6
>>> (7 - 3).doSomethingElse()
>>>
The automatic type conversion here is important. As far as I am aware, none of the languages today allow you to mess with integers this much.
In the end, you can do in your code whatever. As long as the people reading it can understand immediately. So the polymorphic dispatch on integers or anything unordinary must have really good reasoning behind it.