Inheritance vs specific types in Financial Modelling for cashflows - c++

I have to program some financial applications where I have to represent a schedule of flows. The flows can be of 3 types:
fee flow (just a lump payment at some date)
floating rate flow (the flow is dependant of an interest rate to be determined at a later date)
fixed rate flow (the flow is dependant of an interest rate determined when the deal is done)
I need to keep the whole information and I need to represent a schedule of these flows.
Originally I wanted to use inheritance and create three classes FeeFlow, FloatingFlow, FixedFlow all inheriting from ICashFlow and implement some method GetFlowType() returning an enum then I could dynamic_cast the object to the correct type.
That would allow me to have only one vector<IFlow> to represent my schedule.
What do you think of this design, should I rather use three vectors vector<FeeFlow>, vector<FloatingFlow> and vector<FixedFlow> to avoid the dynamic casts ?

Why do you actually need the dynamic casts? Make your flow subclasses implement the same interface polymorphically, then there is no need to cast anything.
If they need very different inputs, you could try passing the different inputs as constructor parameters, thus clearing up the common interface. However, if you really can't define a common interface for them, maybe they are better implemented as independent classes.

If all the operations you need to do with the different types of the flow differ only by the underlying data, i would suggest extending the ICashFlow with such operations - then no dynamic casting is needed. If however this is not possible, then both options are ok i think. I personally would choose the one with the three vectors, if there is no other hidden need for one vector of base classes.

I think the strategy pattern would suit you best.
You implement a CashFlow class that contains a CashFlowStrategy property which does the processing.
I do not fully understand the requirements and the differences between the flows but something like this might work (meta-c++, not valid code):
class CashFlowStrategy {
public:
virtual void ProcessFlow(Account from, Account to);
}
class FixedRateCashFlowStrategy : public CashFlowStrategy {
public:
void ProcessFlow(Account from, Account to) { ... }
}
class CashFlow {
private:
CashFlowStrategy strategy;
public:
CashFlow(CashFlowStrategy &strategy) { this->strategy = strategy; }
void Process() { this->strategy->ProcessFlow(this->from, this->to); }
}
You only need the std::vector<CashFlow>, the decision of how to do the processing is hidden in the strategy so you shouldn't have to care about it.

It sounds like you have various schedules and various types of deposits, which collectively make up a financial flow. The solution sounds as if a strategy pattern may work for both schedule and deposit behavior. Although, if you have room, it might be worth considering a functional approach. A lambda expression would give you the same logic with a tenth of the code ...

Related

Strategy pattern vs Inheritance

We have some algo to apply over some data, and the algo may get applied multiple times on same data. We have two ways to do this:
Keep data and logic seperate
class Algo{
public:
virtual int execute(data_object) = 0;
};
class AlgoX: public Algo{
public:
int execute(data_object);
};
class AlgoY: public Algo{
public:
int execute(data_object);
};
class Data{
public:
string some_values;
...
void* algo_specific_data; //It will contain some algo specific data (like state of algo)
Algo* algo_ptr; //Reference of Algo
int execute(){
algo_ptr->execute(this);
}
};
some_function(){
Data* data_object = create_data(algo_ptr, algo_specific_data); //A dummy function which creates an object of type data.
data_object->execute();
}
Bind data and logic by inheritance
class Data{
public:
string some_values;
...
virtual int execute() = 0;
};
class DataWithAlgoX : public Data{
public:
AlgoX_Relateddata algo_related_data; //some algo specific data (like state of algo)
int execute();
}
class DataWithAlgoY : public Data{
public:
AlgoY_Relateddata algo_related_data; //some algo specific data (like state of algo)
int execute();
}
some_function(){
Data* data_object = create_data(algo_type); //A dummy function which creates an object of type data.
data_object->execute();
}
Which design is better, if
We can change algo type between the multiple calls of algo->execute() on data
(But switching will not be very frequent, and needed only in some specific scenario).
Some people may point out that switching of algo will make us to recreate the data_object.
We are willing to take that extra burden if architecture 2 is much better than 1.
We will not change algo type ever between the multiple calls of algo->execute() on data .
Mixing Data and Algorithm in the same class in (very) bad practice.
In breaks the Single Resposability Principle.
https://en.wikipedia.org/wiki/Single_responsibility_principle
If you want to combine multiple types of Data with multiple Algorithms
use something like a Mediator. The idea is to define Data and Algorithms separately and define the interaction between them in the mediator.
https://en.wikipedia.org/wiki/Mediator_pattern
In my opinion, design 2 is MUCH worse then 1. And even in the case of design 1, I would remove the reference to the algorithm in the Data class. It only introduces High Coupling, i. e. a dependecy between the classes which make one affected bt the changes in the other:
https://en.wikipedia.org/wiki/Coupling_(computer_programming)
(and google "Low coupling, high cohesion", it is another OOP principle).
The Mediator would solve the coupling problem too.
I would prefer keeping Algo separate from Data always. In general Same data could be used for different Algo and same Algo can be used on different Data. So if you are implementing it as an inheritance chances are high that it will lead to code duplication or combinatorial explosion of subclasses like DataWithAgloA DataWithAlgoB.
More importantly Data provider i.e the system which generates data might not need to know about complex algorithms to be used there. It could be very well dumb system to generate data and there could be researchers who are updating the Algo. Keeping Data and Algo essentially violates Single Responsible Principle. Now your DataWithAlgo class has 2 axis of change (As uncle bob would say) from Algo and from Data.
Keeping Data and Algo separate keeps both the code nimble and easy to change and also satisfy SRP. This reduce coupling in the code, avoids any combinatorial explosion. So I would always go segregating Algo from Data.
Strategy pattern vs Inheritance
Between these two, favor the first over the latter. In inheritance, not only are you inheriting the API contract, you're also inheriting behavior, which may or may not be possible to override. And in your case, since you state that multiple algorithms may be applied to the same class today but not necessarily tomorrow, applying inheritance this way will lead to an explosion of classes and duplicate code, as you've shown.
However,
We have two ways to do this
How come? Have you considered the Decorator Pattern (my favorite)? Depending on how your data nodes are structured, perhaps even the Visitor Pattern is a valid choice.
I would also caution against the blanket "mixing data and algorithm always breaks SRP" advise generally thrown around. You introduce "2 axis of change" only when the use-case actually arises. Ideally, if you have perfect encapsulation, there is no reason why a type can't handle and apply algorithms to its own data. This depends on the domain; in your case, this clearly does not (seem to?) apply.

Typesafe method for retrieving data of unknown type through interface

TL;DR version:
I am designing a class in C++14 to be generic. Below I describe a design problem, and I would be grateful for a solution to implement what I'm trying, or a suggestion for a redesign.
Say the class I'm designing is called Algo. Its constructor is passed a unique_ptr to a type, say Business, which implements an interface (i.e., inherits from a pure virtual class) and does most of the serious work.
I want an object of type Algo to be able to return a pointer (or even a copy) of a data member from the Business object that it owns. But it can't know the type that Business will want to return. I expect the owner of Algo to know what will come out based on what Business he passed in.
In my C days, I would blow off the type system by passing around void* and casting as needed. But that sort of thing now wreaks to me.
More detail:
So, a sort of pseudo-C++14 implementation of the above situation might look like:
// perhaps a template here?
class AbstractBusiness {
. . .
public:
?unknownType? result();
};
class Algo {
//Could be public if needbe.
unique_ptr<AbstractBusiness> concreteBusiness_;
public:
Algo(std::unique_ptr<AbstractBusiness> concreteBusiness);
auto result() {return concreteBusiness_.result();}
};
class Business : public AbstractBusiness {
. . .
public:
std::valarray<float> data_;
std::valarray<float> result() {return data_;}
};
:::
auto b = std::unique_ptr<AbstractBusiness>{std::move(new Business())};
Algo a(std::move(b));
auto myResult = a.result();
In this example, myResult will be a std::valarray<float>, but I don't want Algo or the AbstractBusiness interface to have to know that! The creator of b and a should be in charge of knowing what should come out of a.result().
If I am taking a wrong turn in this design, don't hesitate to let me know. I'm a bit green at this point and very open to suggestions.
I've tried...
I obviously can't use auto for a virtual method, nor have a template in a virtual class. These are the only things that stood out.
I'm playing with the idea of making a container interface for whatever Business.result() returns, and just passing pointers to abstract type up to Algo.result(). But I'm starting to feel like there may be a better way, so I'm on here begging for suggestions.
You haven't actually described a design problem. You've described some
implementation choices that you've gone with and a roadblock you've
run into, but we don't know the reasons for the choices.
You tell us that Algo takes ownership of a business via a pointer to a
polymorphic interface AbstractBusiness and must provide a getter for
that business's data, though it doesn't know the concrete type of that
data (because it doesn't know the concrete type of the business).
Neither of these questions have evident answers:-
Why should Algo acquire a business via a polymorphic interface?
Why should Algo provide a getter for the data of its business?
But deciding it must be so leads to the roadblock.
The polymorphic pothole and how to get out it
Q1. leads us to wonder what is the motivation for AbstractBusiness? Platitudinously, it's safe to say you want it to provide a uniform interface for manipulating and querying all sorts of businesses of concrete types that may be determined at runtime.
To be fully fit for that purpose, AbstractBusiness will encapsulate a necessary and sufficient interface for discharging all of the operations and queries on concrete businesses that applications (including but not limited to your own) can reasonably be expected to need. Call that Plan A. What you have discovered is that it isn't fully fit for Plan A. If the application needs at times to manipulate or query "the data" of a business that is represented to it via an AbstractBusiness, then the AbstractBusiness interface needs to provide polymorphic methods to discharge all of those manipulations and queries, and each concrete business class needs to implement them appropriately for the type of data it contains.
Where your AbstractBusiness has the problematic:
?unknownType? result();
you need to code virtual methods that address all of the convincing answers to the question: What might an application want to know about the notional result() , or do to it?
In this light, the suggestion that has been canvassed to introduce another polymorphic interface, AbstractData, ancestral to all of the concrete data types of all the concrete businesses, may be viewed as a suggestion to compensate for the necessary methods that are missing from AbstractBusiness by separately encapsulating them in a rescue abstraction. Better to finish the unfinished AbstractBusiness.
This is all good and scriptural perhaps, but maybe what has actually stopped you from finishing AbstractBusiness already is the perception that the data of BusinessX can be essentially different from that of BusinessY, so that it is impossible to devise a single set of polymorphic methods that is necessary and sufficient to manage both.
If this is the case, it tells you that businesses cannot all be managed through a single abstract interface. AbstractBusiness can't be fully fit for that purpose and, if it has a role, its role can only be to manage polymorphic objects that represent more specialized abstractions, BusinessTypeX, BusinessTypeY, etc., within each of which the variety, if any, of concrete types can be accommodated by a single polymorphic interface.
AbstractBusiness will then present only the interface that is shared
by all businesses. It will have no result() at all and a caller who obtains a pointer to AbstractBusiness with the intention of doing something with
with the thing returned by BusinessTypeX::result() will proceed by dynamically casting the source pointer to BusinessTypeX *, and calling result() through the target pointer only if its not null.
We still do not know what is the motivation of AbstractBusiness. We've just pursued the fairly plausible thought that you have "textbook" ambitions for it - Plan A - and have either failed to realize that you just haven't finished it, or you have grasped that the diversity of the data you're dealing with prevents you from finishing it per Plan A, and don't have a Plan B. Plan B is: Deepen the polymorphic hierarchy and use dynamic_cast<LowerType *>(HigherType *) to secure safe access to the LowerType interface when it outruns the HigherType one. [1]
The turn of Q2. now. Most likely, the reason for Algo::result() is simply: Because it's the done thing for a class to provide getters that directly
answer the client's natural queries, and in this case a natural query is for the data owned by the business that is owned by the Algo. But if the Algo knows its business only as an AbstractBusiness, then it just can't return the data owned by its business, because the reasons already seen mean that AbstractBusiness can't return "the data" to the Algo, or to anything else.
Algo::result() is misconceived identically as AbstractBusiness::result() is misconceived. Given that BusinessXs data and BusinessYs data might need to be queried either through some repertoire of virtual methods that are still TODO in AbstractBusiness (Plan A), or perhaps through methods of BusinessX and BusinessY that are not inherited from AbstractBusiness at all (Plan B), the only query that Algo certainly can and should support with respect to its business is to return the AbstractBusiness pointer
through which it owns its business, leaving it to the caller to query through the pointer or downcast it, if they can, to a lower-type interface they want query. Even if it is possible to finish AbstractBusiness per Plan A, the idea that the missing reportoire of methods should all be duplicated in the interface of Algo just so that a caller never has to receive and downcast an AbstractBusiness pointer is uncompelling. Would every type that manages an AbstractBusiness pointer follow suit?
Summarizing thus far, if AbstractBusiness has a good reason to exist, then you need either to finish it per Plan A, and work through the repercussions of so doing, or else curtail it short of attempting to be a sufficient interface for managing all businesses and bolster it with an enriched polymorphic hierarchy that clients negotiate by dynamic casting, per Plan B; and in either case you should be content for Algo and similar jobsworths in the AbstractBusiness trade just to return their AbstractBusiness pointer to clients who have specialized uses for it.
Better than that, don't go there
But the question of whether AbstractBusiness has a good reason to exist is still dangling, and should you find yourself driven to Plan B that in itself will make the question more pointed: when it transpires that an abstract interface, cast as the root class of a single inheritance hierarchy, cannot deliver Plan A then a doubt arises about the wisdom of the architecture it figures it. Dynamic casting to detect and acquire interfaces is a clunky and expensive mode of flow control and especially vexatious when - as you tell us is your situation - a scope that will have to perform the downcasting rigmarole already knows the type it should "get out" is the type it "put in". Do all the types that are imperfectly descended from the root abstraction need to have a single ancestor, for a reason other than uniformity of interface (since it doesn't give them that)? The economies of generic interfaces are an ever-present goal, but is runtime polymorphism
the right means, or even one of the right means, to realize them in the context of your project?
In your code-sketch, AbstractBusiness serves no end purpose but to furnish a
type that can uniformly fill certain slots in class Algo, with the effect that Algo can operate correctly on any type that exhibits certain traits and
behaviours. As sketched, Algos only requirement of a qualifying type is
that it shall have a result() method that returns something: it doesn't care what. But the fact that you express Algos requirements upon a qualifying type by specifying that it shall be an AbstractBusiness prohibits it from not caring what is returned by result(): AbstractBusiness cannot do that result() method, although any of its descendants might do.
Suppose in that case that you sack AbstractBusiness from the job of enforcing the generic attributes of types on which Algo can operate and let Algo itself do that instead, by making it a template? - since it looks as if what AbstractBusiness is doing for Algo is serving the purpose of a template parameter but sabotaging that very purpose:
#include <memory>
template<class T>
class Algo {
std::unique_ptr<T> concreteBusiness_;
public:
explicit Algo(T * concreteBusiness)
: concreteBusiness_{concreteBusiness}{};
auto result() { return concreteBusiness_->result(); }
};
#include <valarray>
#include <algorithm>
struct MathBusiness {
std::valarray<float> data_{1.1,2.2,3.3};
float result() const {
return std::accumulate(std::begin(data_),std::end(data_),0.0);
}
};
#include <string>
struct StringBusiness {
std::string data_{"Hello World"};
std::string result() const { return data_; }
};
#include <iostream>
int main()
{
Algo<MathBusiness> am{new MathBusiness};
auto ram = am.result();
Algo<StringBusiness> as{new StringBusiness};
auto ras = as.result();
std::cout << ram << '\n' << ras << '\n';
return 0;
}
You see that in this way of transferring the genericity from AbstractBusiness to Algo, the former is left completely redundant, and so removed. This is a nutshell illustration of how the introduction of templates changed the game of C++ design root and branch, making polymporhic designs obselete for most of their prior applications to the crafting of generic interfaces.
We are working from a sketch of your problem context: perhaps there remain good reasons not in sight for AbstractBusiness to exist. But even if there are, they don't per se constitute reasons for Algo not to be a template or to have any dependency on AbstractBusiness. And perhaps they can one by one be eliminated by similar treatments.
Making Algo into a template still might not be a viable solution for you, but if it isn't then there is essentially more to the problem than we have seen. And anyhow take away this rule of thumb: Templates for generic interfaces; polymorphism for runtime adaptation of an interface's behaviour.
[1] What might look like another plan is to encapulate "the data" of each concrete
business in a boost::any or std::experimental::any. But you can probably
see straightaway that this is essentially the same as the idea of encapsulating
the data in a rescue abstraction, using an off-the shelf Swiss Army abstraction,
rather than crafting your own. In either guise, the idea still leaves
callers to downcast the abstraction to the type of real interest to find out
if that's what they've got, and in that sense is a variant of Plan B.
There are several ways to go at this. The easiest way is to not pass the ownership but call Algo by reference:
Business b;
Algo(b);
auto result = b.get_result();
However, sometimes this is not possible. In that case various options open up that can become quite complicated. Let me start with the most versatile and complicated one:
If you know all the types that derive from AbstractBusiness you could use the visitor pattern:
First we declare an abstract method accept in AbstractBusiness that takes a BusinessVisitor. This visitor will be responsible to handle the different types and perform an action based on which type it is visiting:
class BusinessVisitor;
struct AbstractBusiness {
virtual ~AbstractBusiness() = default;
virtual void accept(BusinessVisitor&) const = 0;
};
The BusinessVisitor looks like this:
class BusinessOne;
class BusinessTwo;
struct BusinessVisitor {
virtual ~BusinessVisitor() = default;
virtual void on_business_one(const BusinessOne&) {};
virtual void on_business_two(const BusinessTwo&) {};
};
Some people prefer to call all methods in the visitor visit and let overload resolution do the rest but I prefer more explicit names.
struct BusinessOne {
void accept(BusinessVisitor& v) const {
v.on_business_one(*this);
}
};
struct BusinessTwo {
void accept(BusinessVisitor& v) const override {
v.on_business_two(*this);
}
};
Now we can add an accept method to Algo as well. This one will simply dispatch to the contained AbstractBusiness object.
class Algo {
std::unique_ptr<AbstractBusiness> b_;
public:
Algo(std::unique_ptr<AbstractBusiness> b);
void accept(BusinessVisitor& visitor) const override {
return b_->accept(visitor);
}
};
To get the result for a specific business type we need to define a visitor that handles this type:
struct BusinessOneResult : public BusinessVisitor {
void on_business_one(const BusinessOne& b) {
// save result;
}
/* ... */ get_result() const;
};
Now we can run Algo and retrieve the result:
auto b = std::unique_ptr<AbstractBusiness>(new BusinessOne());
Algo a(std::move(b));
BusinessOneResult visitor;
a.accept(visitor);
auto result = visitor.get_result();
The real power of this approach unfolds if you don't want extract a specific value from Algo but if you want to trigger an action. In that case the action is usually different depending on the business type, thus the whole action can be specified in the visitor.
A different and quite elegant way would be to use a std::future:
struct Business {
std::future</*...*/> get_future_result() {
return promise_.get_future();
}
void some_method() {
// ...
promise_.set_value(...);
}
private:
std::promise</*...*/> promise_;
};
// Must use Business here (AbstractBusiness doesn't know about the
// type of the future).
auto b = std::unique_ptr<Business>(new Business());
auto future = b.get_future_result();
Algo a(std::move(b));
auto result = future.get();
Another way would be to wrap the type in a class derived from a tag class (no methods or data members) and dynamic_cast it to the type you know it contains. Using dynamic_cast it's usually frowned upon but it has it's uses.
std::any or boost::any would be another way to go.
Note: I dropped the std::move for the argument of the std::unique_ptr constructor, it doesn't do a thing there: The result of the new operation is already an rvalue and moving a pointer is as efficient as copying it.

Observer Pattern For Different Observables

I was wondering what the appropriate way of dealing with Observables that may contain different data. To use the weather data analogy:
suppose I have different weather stations that record data. Let's say humidity, temperature and pressure. One station might only have the capability of recording temperature, while others all three etc..
What I am trying to do is the following:
An observer specifies what data they want to record. Say, only temperature.
An observable specifies what data they have available.
If both the observer and observable match up, the data is processed by the observable.
Here are a few things:
There are a lot more parameters than 3. Something like 30, and this can grow. I thought of implementing getTemperature(), getPressure(), getHumidity(), etc.. in my base observable and overriding them in the relevant classes. Otherwise it returns nothing. I also created a Flags anonymous struct that is specified for both the Observable and Observer, and only when they match data is recorded.
I wanted to know the following:
Is this the best design? Should the responsibility of matching Flags be on the Observer? Is there a more elegant solution?
I'm not necessarily looking for code handouts. Just thoughts on a good implementation.
Thanks!
Since you already have Flags that identifies the kinds of things that can be observed, i.e.
enum Measurement {
Temperature = 0x00001
, Humidity = 0x00002
, Pressure = 0x00004
};
you might reuse it to identify the measurements through data, as opposed to identifying them through method names. In other words, instead of making the interface that looks like this
struct observable {
Measurement provides() {
return Temperature | Humidity | Pressure;
}
double getTemperature() ...
double getHumidity() ...
double getPressure() ...
};
do it like this:
struct observable {
Measurement provides() {
return Temperature | Humidity | Pressure;
}
double measure(Measurement measurementId) {
...
}
};
This would give you a uniform interface, with observers and observables matched entirely through data.
However, all implementations of measure would need to "dispatch" based on a number in something that looks like a switch, which is not ideal. There is a solution to this: you could put a single, non-virtual implementation in the base class, and use regular virtual dispatch after that:
struct observable_base {
double measure(Measurement measurementId) {
switch(measurementId) {
case Temperature: return getTemperature();
case Humidity: return getHumidity();
case Pressure: return getPressure();
}
return 0;
}
protected:
virtual double getTemperature() { return 0; }
virtual double getHumidity() { return 0; }
virtual double getPressure() { return 0; }
};
From my experience, it's best to use Object-oriented design for the Observer pattern.
You can create an Observer < Weather > and an Observable < Weather > with a single object that is observed, a Weather object. Pseudocode sample:
public class Weather()
{
... Temperature
... Pressure
... Humidity
}
If a given implementation has more than one observable piece of data, just have it implement the Observable for that type also.
So, you could have a ColorableWeatherState object that is both Observable < Weather > and Observable < Color > and could be subscribed to by both observers who care about color and by observers who care about weather. They could be separate. They could be the same object. It's up to you to determine the implementation.
First of all, the following is my opinion. There are a lot of ways to solve your problem and maybe others are better. I tell you how I solute such kind of problems.
I would not define a base observable with all possible methods, that is bad style. A base class should only define Methods, it fulfill. Additionally it is hard to extend, you have to code observer and observables at the same time and have to compile it both. In case of using additional communication layers in the future, like networking, it is even harder to abstract.
If your values have the same type, use one getter method and give it a parameter to select the result:
double getValue(enumMyValueType type);
if you have different types, e.g. strings and doubles, I would use a kind of variants (like boost::variants) not like getValueDoublesand getValueString. Different getters only distinguished by type should be avoided in your case. Keep your observable class small and stable. Extending it with new values like color or oxygen is easy without recode the whole path if you use an own return type.
Defining an own return type class is better than define a big baseclass for observables as you can put together several information regarding to the value like:
temperature
source
timestamp
and
pressure
source
timestamp
extending the type do not affect your observer and observables they are still lightweight.
At last. Only the Observer should decide what he want and if he match or not. The observer should ask the observables and decide what and where to register. An observable should not need to know what the observer want. Any negotiation system I saw until now failed (in case of DirectShow it failed badly).
This might be a bad answer, but I wonder why can't we make observables return a struct of variables(or pointers to them), with invalid fields set to NaN(or Null for pointers) or some other identifier.
One problem I can see is that, it will force the observable to provide everything regardless what the observer requests.
Then what about:
On a get() call to observable, it returns a struct of function pointers to data getters. If the observable can provide that data, then the getter is not Null. Then the observer can pick a getter, check if it's null, then finall get the data it wants.

Accessing subclass functions of member of collection of parent class objects

(Refer Update #1 for a concise version of the question.)
We have an (abstract) class named Games that has subclasses, say BasketBall and Hockey (and probably many more to come later).
Another class GameSchedule, must contain a collection GamesCollection of various Games objects. The issue is that we would, at times, like to iterate only through the BasketBall objects of GamesCollection and call functions that are specific to it (and not mentioned in the Games class).
That is, GameSchedule deals with a number of objects that broadly belong to Games class, in the sense that they do have common functions that are being accessed; at the same time, there is more granularity at which they are to be handled.
We would like to come up with a design that avoids unsafe downcasting, and is extensible in the sense that creating many subclasses under Games or any of its existing subclasses must not necessitate the addition of too much code to handle this requirement.
Examples:
A clumsy solution that I came up with, that doesn't do any downcasting at all, is to have dummy functions in the Game class for every subclass specific function that has to be called from GameSchedule. These dummy functions will have an overriding implementation in the appropriate subclasses which actually require its implementation.
We could explicitly maintain different containers for various subclasses of Games instead of a single container. But this would require a lot of extra code in GameSchedule, when the number of subclasses grow. Especially if we need to iterate through all the Games objects.
Is there a neat way of doing this?
Note: the code is written in C++
Update# 1: I realized that the question can be put in a much simpler way. Is it possible to have a container class for any object belonging to a hierarchy of classes? Moreover, this container class must have the ability to pick elements belonging to (or derive from) a particular class from the hierarchy and return an appropriate list.
In the context of the above problem, the container class must have functions like GetCricketGames, GetTestCricketGames, GetBaseballGame etc.,
This is exactly one of the problems that The "Tell, Don't Ask" principle was created for.
You're describing an object that holds onto references to other objects, and wants to ask them what type of object they are before telling them what they need to do. From the article linked above:
The problem is that, as the caller, you should not be making decisions based on the state of the called object that result in you then changing the state of the object. The logic you are implementing is probably the called object’s responsibility, not yours. For you to make decisions outside the object violates its encapsulation.
If you break the rules of encapsulation, you not only introduce the runtime risks incurred by rampant downcasts, but also make your system significantly less maintainable by making it easier for components to become tightly coupled.
Now that that's out there, let's look at how the "Tell, Don't Ask" could be applied to your design problem.
Let's go through your stated constraints (in no particular order):
GameSchedule needs to iterate over all games, performing general operations
GameSchedule needs to iterate over a subset of all games (e.g., Basketball), to perform type-specific operations
No downcasts
Must easily accommodate new Game subclasses
The first step to following the "Tell, Don't Ask" principle is identifying the actions that will take place in the system. This lets us take a step back and evaluate what the system should be doing, without getting bogged down into the details of how it should be doing it.
You made the following comment in #MarkB's answer:
If there's a TestCricket class inheriting from Cricket, and it has many specific attributes concerning the timings of the various innings of the match, and we would like to initialize the values of all TestCricket objects' timing attributes to some preset value, I need a loop that picks all TestCricket objects and calls some function like setInningTimings(int inning_index, Time_Object t)
In this case, the action is: "Initialize the inning timings of all TestCricket games to a preset value."
This is problematic, because the code that wants to perform this initialization is unable to differentiate between TestCricket games, and other games (e.g., Basketball). But maybe it doesn't need to...
Most games have some element of time: Basketball games have time-limited periods, while Baseball games have (basically) innings with basically unlimited time. Each type of game could have its own completely unique configuration. This is not something we want to offload onto a single class.
Instead of asking each game what type of Game it is, and then telling it how to initialize, consider how things would work if the GameSchedule simply told each Game object to initialize. This delegates the responsibility of the initialization to the subclass of Game - the class with literally the most knowledge of what type of game it is.
This can feel really weird at first, because the GameSchedule object is relinquishing control to another object. This is an example of the Hollywood Principle. It's a completely different way of solving problems than the approach most developers initially learn.
This approach deals with the constraints in the following ways:
GameSchedule can iterate over a list of Games without any problem
GameSchedule no longer needs to know the subtypes of its Games
No downcasting is necessary, because the subclasses themselves are handling the subclass-specific logic
When a new subclass is added, no logic needs to be changed anywhere - the subclass itself implements the necessary details (e.g., an InitializeTiming() method).
Edit: Here's an example, as a proof-of-concept.
struct Game
{
std::string m_name;
Game(std::string name)
: m_name(name)
{
}
virtual void Start() = 0;
virtual void InitializeTiming() = 0;
};
// A class to demonstrate a collaborating object
struct PeriodLengthProvider
{
int GetPeriodLength();
}
struct Basketball : Game
{
int m_period_length;
PeriodLengthProvider* m_period_length_provider;
Basketball(PeriodLengthProvider* period_length_provider)
: Game("Basketball")
, m_period_length_provider(period_length_provider)
{
}
void Start() override;
void InitializeTiming() override
{
m_period_length = m_time_provider->GetPeriodLength();
}
};
struct Baseball : Game
{
int m_number_of_innings;
Baseball() : Game("Baseball") { }
void Start() override;
void InitializeTiming() override
{
m_number_of_innings = 9;
}
}
struct GameSchedule
{
std::vector<Game*> m_games;
GameSchedule(std::vector<Game*> games)
: m_games(games)
{
}
void StartGames()
{
for(auto& game : m_games)
{
game->InitializeTiming();
game->Start();
}
}
};
You've already identified the first two options that came to my mind: Make the base class have the methods in question, or maintain separate containers for each game type.
The fact that you don't feel these are appropriate leads me to believe that the "abstract" interface you provide in the Game base class may be far too concrete. I suspect that what you need to do is step back and look at the base interface.
You haven't given any concrete example to help, so I'm going to make one up. Let's say your basketball class has a NextQuarter method and hockey has NextPeriod. Instead, add to the base class a NextGameSegment method, or something that abstracts away the game-specific details. All the game-specific implementation details should be hidden in the child class with only a game-general interface needed by the schedule class.
C# supports reflections and by using the "is" keyword or GetType() member function you could do these easily. If you are writing your code in unmanaged C++, I think the best way to do this is add a GetType() method in your base class (Games?). Which in its turn would return an enum, containing all the classes that derive from it (so you would have to create an enum too) for that. That way you can safely determine the type you are dealing with only through the base type. Below is an example:
enum class GameTypes { Game, Basketball, Football, Hockey };
class Game
{
public:
virtual GameTypes GetType() { return GameTypes::Game; }
}
class BasketBall : public Game
{
public:
GameTypes GetType() { return GameTypes::Basketball; }
}
and you do this for the remaining games (e.g. Football, Hockey). Then you keep a container of Game objects only. As you get the Game object, you call its GetType() method and effectively determine its type.
You're trying to have it all, and you can't do that. :) Either you need to do a downcast, or you'll need to utilize something like the visitor pattern that would then require you to do work every time you create a new implementation of Game. Or you can fundamentally redesign things to eliminate the need to pick the individual Basketballs out of a collection of Games.
And FWIW: downcasting may be ugly, but it's not unsafe as long as you use pointers and check for null:
for(Game* game : allGames)
{
Basketball* bball = dynamic_cast<Basketball*>(game);
if(bball != nullptr)
bball->SetupCourt();
}
I'd use the strategy pattern here.
Each game type has its own scheduling strategy which derives from the common strategy used by your game schedule class and decouples the dependency between the specific game and game schedule.

What does "data abstraction" exactly mean?

What does data abstraction refer to?
Please provide real life examples alongwith.
Abstraction has two parts:
Hide details that don't matter from a certain point of view
Identify details that do matter from a certain point of view and consider items to be of the the same class if they possess those details.
For example, if I am designing a program to deal with inventory, I would like to be able to find out how many items of a certain type the system has in stock. From the perspective of the interface system, I don't care if I am getting this information from a database, a csv file, a remote repository via a SOAP interface or punch cards. I just care that I can can say widget.get_items_in_stock() and know that it will return an integer.
If I later decide that I want to record that number in some other way, the person designing the interface doesn't need to know, care or worry about it as long as widget still has the get_items_in_stock() method. Like wise, the interface doesn't need to care if I subclass the widget class and add a get_square_root_of_items_in_stock() method. I can pass an instance of the new class to it just as well.
So in this example, we've hidden the details of how the data is acquired and decided that anything with a get_items_in_stock() method is an instance of the same class (or a subclass thereof) for certain purposes.
Data abstraction is any device that allows you to treat data as humans encounter it rather than as it is stored on machine.
At the lowest level, all primitive data types are abstractions -- as programmers, we don't usually have to deal with data at the bit level (which is how it is ultimately stored) but as integers, floating point numbers, characters, etc.
We then add layers onto that abstraction -- maybe two integers represents a Point, or we and enumerations to represent the months of the year, days of the week, etc.
With each abstraction layer, we move further from the machine and (hopefully) closer to human understanding of the data. This can extract a performance penalty -- it may not always be the case that points can be most efficiently represented by two integers. This is compensated for by the shorter development (and maintenance) time when abstractions are used.
The technique of creating new data type that is well suited to an application to be programmed is known as data abstraction.
Abstraction means providing only essential information to the outside world and hiding their background details..examp. In ur Computer u can see only monitor, keyboard nd mouse..u don't know anything about internal wiring this is abstraction.
Data abstraction seems to be explained as breaking data down as far as you can get it. food would be the abstraction of apple, orange, pizza. animal would be the abstraction of cat, cow, pig. A food object would be something like this pseudo code:
class food{
name;
calories;
weight;
public eat(name);
}
all foods have a name, calorie amount, and a weight. That's pretty abstract.
You could then make objects that inherit, which would be a bit less abstract.
class pizza inherits food{
toppings;
say_toppings();
}
pizza now has toppings, but it inherits name, calories, and weight from food.
basically abstraction has been explained as getting to the lowest level of each item and making classes that extend from them. It makes your code more reusable too... If you've bade your base class of food well enough, and included everything abstract about it anyone working in the food industry could use your class.
Abstraction is hiding the skeleton from the human body. The skin does a great way of containing it. (See how abstract I'm being there? Pun intended. I digress...)
If I have a water bottle, then I'm able to drink from it by opening the lid, twisting it until it pops off.
bool lid_open = false;
void open_water_bottle_by_twisting() { lid_open = true; }
But water bottles are containers. Containers hold liquids until they become open and they are able to be drunk from (assuming the liquid is drinkable).
class Container
{
bool lid_open = false;
protected:
Container() {}
void open_by_twisting()
{
lid_open = true;
}
public:
virtual ~Container();
};
class WaterBottle : public Container
{
WaterBottle() : Container() {}
public:
~WaterBottle();
};
However, not all containers are opened the same way. Some containers, such as the water bottle, have lids that can be twisted off. Others don't have lids, such as exercise bottles - those contain bendy straws that can be bent down for storage or up for drinking.
class Container
{
bool lid_open;
bool straw_open;
protected:
void TurnLid() { lid_open = true; }
void BendStraw() { straw_open = true; }
Container() : lid_open(false), straw_open(false){}
public:
virtual void open() = 0;
virtual ~Container();
};
class WaterBottle : public Container
{
public:
WaterBottle() : Container() {}
void open()
{
TurnLid();
}
~WaterBottle();
};
class ExerciseBottle : public Container
{
public:
ExerciseBottle() : Container() {}
void open()
{
BendStraw();
}
~ExerciseBottle();
};
But the client doesn't know what ExerciseBottle's implementation of ExerciseBottle's open() is. It calls BendStraw(), which then sets straw_open to true. But ExerciseBottle simply calls one function to do all of this work. The client doesn't have to perform several actions that are used in the implementation of open(). The case goes similarly for WaterBottle. And that's what abstraction is: letting the client know that the back-end will do all of the work for it. When the term "separating implementation from interface" is used, this is what is meant.
Is the complex system that uses data details which are easy to interact or encounter with humans, which differ from the way computer system stores such as in binary number system.
Answered by Neema, Rohan and Upendo (The programmers)
The technique of limiting the data attributes according to given scenario for development of software and removing all irrelevant attributes.This makes software development simpler.
Let's take one real life example of a TV which you can turn on and off, change the channel, adjust the volume, and add external components such as speakers, VCRs, and DVD players BUT you do not know it's internal detail that is, you do not know how it receives signals over the air or through a cable, how it translates them, and finally displays them on the screen.
It refers to the act of representing essential feature without including the background detail or the explanation
It is difficult to find day to day life example of DATA abstraction. However, any data types in programming language, tables and view in DBMS, data structures like LinkedList, List, Queue, Stack are data abstractions. These abstractions provide you the way to access the data in particular manner.
This article may help you understand data abstraction and control abstraction in depth. It also has some of the real life examples of control and data abstractions.
Abstraction rrefers to the act of representing essential features without including the background detail or explanation.
Simply Data Abstraction is nothing but the hiding unnecessary datails from user.
Example:Person simply just wants to make a call, he just select or dial no. and click on call button this info. is enough for him.He dont want to know about how connection is made and whatever process behind making call or how voice is transferred.
I know this question was asked long time ago. But still like to share one real life example which might help others to understand concept of abstraction very easily.
A real-world analogy of abstraction might work like this: You (the object) are arranging to meet a blind date and are deciding what to tell them so that they can recognize you in the restaurant. You decide to include the information about where you will be located, your height, hair color, and the color of your jacket. This is all data that will help the procedure (your date finding you) work smoothly. You should include all that information. On the other hand, there are a lot of bits of information about you that aren't relevant to this situation: your social security number, your favorite football players all are irrelevant to this particular situation because they won't help your date to find you.
Data Abstraction:
It is used to provide the necessary information to the user and hide the unnecessary information from the user. It is called data abstraction.
It will hide your business logic from outside the world.
Technical Example: Console.WriteLine();
Non Technical Example: TV remote, Car Remote.
More Detail: Data Abstraction with real-time example
data hiding deals the security features of oops. according to this property private data member of a class is accessible or visual only inside the class not outside the class.