I am use to designing my applications using a more database driven approach and now I would like to start from the model. I have the following requirements and would like to get your take on it. It's basically an Activity with points associated with it.
Activity with Super 30 Doctor
Minimum 4 per month
Subtract a point if you do not hit the minimum (4)
1 Point or 2 Points if you go over 6 per month
2 Points when with a local advocate
Activity with 120 Doctor
.5 Points
Activity with Partnership
2 Points
Activity with Follow-Up Partnership Meeting
2 Points
So, I'm trying to decided if I use an inheritance hiearchy here for each activity type or an enumeration off of the activity. So, is each activity responsible for calculating their points (but in some instances then need to know the total activity count to decide) or do I have some scorer component know all the logic.
Any ideas would be great!
I have this design thus far, but I do not know where to handle the Super 30 rules:
public abstract class ActivityBase {
public int Id { get; set; }
public DateTime Date { get; set; }
public abstract double CalculatePoints();
}
public class SuperThirtyActivity : ActivityBase {
public bool WithCE { get; set; }
public bool WithLocalAdvocate { get; set; }
public override double CalculatePoints() {
if (Date.Month == 3 && Date.AddDays(7).Month == 4)
return 1;
else if (WithCE || WithLocalAdvocate)
return 2;
else
return 1;
}
}
public class OneTwentyActivity : ActivityBase {
public override double CalculatePoints() {
return .5;
}
}
public class PartnershipActivity : ActivityBase {
public override double CalculatePoints() {
return 2;
}
}
Now to handle the Super 30 rules, I thought of introducing the following class. However, some of the domain logic is leaking in here. Is this ok or any other ideas??
public class Scorer {
public double CalculateScore(IEnumerable<ActivityBase> activities) {
var score = activities.Select(a => a.CalculatePoints()).Sum();
var count = activities.Count(a => a is SuperThirtyActivity);
if (count < 4)
score--;
else if (count > 6)
score += count;
return score;
}
}
If the activity base class will contain no logic, I recommend making an IActivity interface and make 4 classes to implement it instead of inheritance. IActivity should have a method like CalculatePoints to be implemented by every realizing class.
If you are not going to check for Activity types anywhere in your application I mean if you will never have code like :
if (activity is PartnershipActivity){
//do something
}
else if (activity is FollowUpActivity) {
// do something else
}
and if you are sure there will be no new activity types introduced into the application in the future you may then consider making one Activity class with enum field as you said and do all the checks and calculations you mentioned in its business logic.
Since some of the points are based on aggregated activities, it looks like there is another concept that is not being captured in the object model, ActivityCollection. It is hinted at in the parameter to Scorer.CalculateScore, but perhaps it needs to be made explicit. The ActivityCollection could then calculate the scores since it is holding all of the information necessary.
On the other hand, the Scorer object can probably serve that role just as well. It is OK that the domain logic is in the Scorer object, since it is only the logic necessary for Scorer to do exactly what its name implies. If you keep Scorer, but move the point values from the activity classes into it, then that structure may serve just as well, if not better.
Related
I'm migrating a legacy application from C to C# (.NET Core 5), and implementing more modern software development practices. The C application had literally all of its data in structures in RAM, all of which were globally available. This is great for simple applications but violates the heck out of the principle of encapsulation. The closest equivalent of doing this in an object-oriented fashion is to make the datastore static (which I don't want to do, for obvious reasons).
The application at hand is highly technical and involves a great deal of math. The previous application calculated a lot of derived values (sometimes repeatedly!) on demand, however this doesn't take advantage of multi-threading or caching.
To demonstrate a simpler yet analogous example, let's say we have a program to manage the costs associated with a baseball team. A team has its own fixed operating costs, as well as one manager (who has a salary), and zero to many players (who also each have salaries).
This is my redesigned data model:
public class Team {
public int Costs { get; set; }
public Manager Manager { get; set; }
public HashSet<Player> Players { get; set; }
private int _operatingCosts;
public int OperatingCosts {
get {
return this._operatingCosts;
}
private set {
// Note the private setter -- this should only be recalculated within this
// method from its own values.
this._operatingCosts = value;
}
}
}
public class Manager {
public string Name { get; set; }
public int Salary { get; set; }
}
public class Player {
public string Name { get; set; }
public int Salary { get; set; }
}
The C code would have a function that runs and puts its fingers in all of the arrays, finds the appropriate elements, and adds them up. In the rewritten C# code, MOST of these calculations are reasonably simple, so they probably are best implemented as read-only calculated properties.
public class Manager {
public int MonthlySalary {
get {
return this.Salary / 12;
}
}
}
The challenge comes when trying to calculate the total cost of running the team. This might be a complex operation that I don't want to have to run each time, so I'll want to cache a value and only recalculate it when an event fires. We know which variables cause the change, so we can fire the event from within the dependent properties' setters.
public class Team : INotifyPropertyChanged {
private int _costs;
public int Costs {
get {
return this._costs;
}
set {
this._costs = value;
NotifyPropertyChanged(); // Fire recalculation on cost change.
}
}
public int Name {
get; set; // No INotifyPropertyChanged needed; cached values aren't
// dependent on this.
}
private int _totalOperatingCost;
public int TotalOperatingCost {
get {
return this._totalOperatingCost;
}
private set {
this._totalOperatingCost = value;
}
}
protected void RecalculateCosts() {
this._totalOperatingCost = this.Team.Cost + this.Manager.Salary + this.Players.Sum(p => p.Salary);
}
}
This has been working really well with INotifyPropertyChanged -- I fire a PropertyChanged event on fields that should trigger a recalculation, and the recalculation logic is there and in one place, and all is well.
Now here's the problem: what happens if the manager's salary changes?
public class Manager : INotifyPropertyChanged {
private int _salary;
public int Salary {
get {
return this._salary;
}
set {
this._salary = value;
NotifyParentPropertyChanged();
}
}
}
The Manager class does not contain a reference to the Team to which he belongs. There's a lot of potential for error retaining a backreference from the child bean to the parent when the parent knows about its own children. So if I call NotifyPropertyChanged() here, the Manager will update his own calculations but it has no idea it needs to update on the parent. This is also mostly resolvable using events, but there's a big hitch:
public class Team {
public string Name { ... }
private Manager _manager;
public Manager Manager {
get {
return this._manager;
}
set {
if (this._manager is not null) {
this._manager.PropertyChanged -= ProcessParentPropertyChangedEvent;
}
this._manager = value;
NotifyPropertyChanged();
if (this._manager is not null) {
this._manager.PropertyChanged += ProcessParentPropertyChangedEvent;
}
}
}
public Team() {
if (this.Manager is not null) {
this.Manager.PropertyChanged += ProcessParentPropertyChangedEvent;
}
}
public static void ProcessParentPropertyChangedEvent(object sender, EventArgs e) {
// ^^^^^^ THIS IS A STATIC METHOD, so "this" is unavailable.
//
// When called from Manager.Salary, sender.GetType().Name = "Manager" and
// e can ONLY carry information from the Manager and knows nothing about
// the Team.
//
// Literally nothing in this method knows about the current team, or I believe
// can know about the team to which the manager belongs.
}
}
public class Manager {
private int _salary;
public int Salary {
get {
return this._salary;
}
set {
this._salary = value;
NotifyParentPropertyChanged();
}
}
}
The event fires properly but because the callback method is static, there's no link to the Team whose Manager's salary just updated. Player would have a similar problem, there's no way to inform the Team class that a Player's salary updated since the recalculation would take place within a static method.
Similarly, we could need to add or subtract players from the team as well, which should also force a recalculation of our team costs. I've gone down this road some with INotifyCollectionChanged, but no luck -- we still end up in a static method with no information about where the changes need to be applied to.
I believe my options are as follows:
(1) Include backreferences to parent elements. This seems somewhat straightforward, but there is a lot that can go wrong here, and garbage collection may be one of them. There are probably going to be about a million elements in memory, and I'm not sure how well this would perform by everything basically being in a doubly-connected graph.
(2) I've looked into the Mediator pattern, but I'm not convinced this still solves my problems without a great deal of error-prone accounting. It also requires the Mediator class to be injected into all of my data elements, and requires me to use extensions for base .NET generic collections types -- I don't want to be forced to always use custom types like MyPlayersList or similar, instead of the more common List<Player> -- especially when NOT using the custom list would likely end in a subtle and silent bug when a recalculation just didn't quite pull the right values.
What are my options? Am I forced to carry tons of backreferences throughout the model?
Is there a different model for event handling that I'm not aware of? I've been working with INotifyPropertyChanged because I'm used to it from a WPF context and it's really fast -- 1,000,000 calls in 60 ms on my machine. That said I don't know if there are any other event handling paradigms that exist to handle this type of case.
This seems like way too straightforward an issue to not have appeared and been solved by someone else before. Thanks so much!
I was wondering if I can dynamically add values set in property using override method. I want to add the values (scores) from properties so that in the end, I can get the total points.
here my code
public abstract class player
{
public string nickName { get; set; }
public virtual int computeScore()
{
throw new NotImplementedException();
}
}
public class Bes : player
{
public int initScore =0;
public int score { get; set; }
public int ttlScore { get; set; }
public override int computeScore()
{
return this.ttlScore += this.score;
}
}
It's doubtful that want you want to do is a good idea. But the fact is, it's not really clear what you want to do.
I have a vague sense that you want, every time the score property is set, to add the value to the ttlScore property. If so, then sure...you can do that, but it's a terrible idea. Using a property to represent that operation would be extremely confusing; instead, you should have a method, e.g. named AddScore(), so it's clear reading the code that every time a score is passed to the method, it will be added to the running total.
For example, something like this:
public class Bes : player
{
public int MostRecentScore { get; private set; }
public int TotalScore { get; private set; }
public int AddScore(int score)
{
this.MostRecentScore = score;
return this.TotalScore += score;
}
}
Then the MostRecentScore property will still show whatever the most recent score was, while the TotalScore property will show the running total, but the class members make it clear that you must call AddScore() to report a new score, and that this will take care of updating both properties of interest.
This example of course does not use the virtual aspect of your code example. It's not clear from your question why the computescore() method was in fact made virtual, and it probably doesn't need to be — if you really want the base class to know about scoring, then the score-related properties belong there as well, and none of the members need to be virtual — so I've left it out.
If this does not address your question, please edit your question so that it's more clear what you're trying to do. Provide a good Minimal, Complete, and Verifiable code example that shows clearly what you've tried, along with a detailed and specific explanation of what the code does, and what you want it to do instead.
A project I'm working on would benefit from having a little more abstraction added to it and I'm faced with a problem I can't seem to get past.
Essentially is we have services that can be assigned and consumed, but the rates at which they are consumed are all a little different. This distinction is important for reporting and for scheduling the consumption of these services.
I'm not really sure how to take data I receive from the database and ensure that the correct concrete type is created. Am I overthinking this and there is something easier I can do? The only thing I can think of doing is having a switch statement determine which type to make based on the unit of time specified, but that seems sloppy.
UnitInterval (which I'm welcome to renaming it something that seems less confusing), is supposed to hold the service's consumption unit (1, 15, 30, 60) and then the UnitSize will be minutes, hours, or days. The UnitSizes are held in a reference table and ID'ed with their appropriate text of Day, Minute, Hour. So in my table Minute has an ID = 1, Hour = 2, Day = 3, and depending on if these intervals need to be adjusted they can be in the future.
How do I get something like the UnitSize from the database and ensure the correct implementation? Am I just going about this the entirely wrong way?
Essentially my end game is that I'll have another class which just contains List<WorkableService> that I can use to spit out a report with the correct units, any costing, duration, etc.
public abstract class WorkableService
{
public int UnitSizeId { get; set; }
public string UnitSizeText { get; set; }
public double UnitInterval { get; set; }
public abstract TimeSpan Duration { get; }
public double UnitsAvailable { get; set; }
public double Adjustment { get; set; }
public decimal Rate { get; set; }
}
public class MinuteService : WorkableService
{
public override TimeSpan Duration
{
get
{
return TimeSpan.FromMinutes(UnitInterval);
}
}
}
public class HourlyService : WorkableService
{
public override TimeSpan Duration
{
get
{
return TimeSpan.FromHours(UnitInterval);
}
}
}
public class DailyService : WorkableService
{
public override TimeSpan Duration
{
get
{
return TimeSpan.FromDays(UnitInterval);
}
}
}
The switch method is totally valid, if you know for sure at compile time all the options you might need. More basic info at the Wikipedia factory pattern, but switching on an enum value or a string identifier is the general concept.
Alternatively, look into Activator.CreateInstance, which you can use to create a new object based on the type's name that you might dynamically load from the database. We do that in some situations to let us add new supported types without recompiling the base service.
The switch statement you refer to as sloppy is something called the Factory pattern. Assuming your WorkableService base constructor takes UnitInterval:
static class WorkableServiceFactory
{
public static WorkableService Get(int unitSizeId, double unitInterval)
{
switch (unitSizeId)
{
case 1:
return new MinuteService(unitInterval);
case 2:
return new HourlyService(unitInterval);
case 3:
return new DailyService(unitInterval);
default:
throw new ArgumentOutOfRangeException("unitSizeId");
}
}
}
I'm usually not a fan of factories (they're the butt of every Java EE joke in the book for a reason), but this is actually a valid scenario for it.
I've been programming in C# (as well as a few other languages) for some time now, but just recently decided that I should start writing custom classes to get a better feel for Object-Oriented Programming. To that end, I started with a base class of Vehicle, and some derived classes, to work on inheritance.
What I'm trying to do here is set up some default values and logic in the base calss of Vehicle, while having the derived classes implement some information which determines the differences. For example, while I set up the _wheelsNumber, _motorType, and _horsePower variables and logic in the base class, I would have each class (Car, Truck, Semi, Moped, etc.) set its _wheelsNumber and trigger the flow of logic to calculate out the rest of the properties.
However, I'm not sure I've built my classes in the right fashion to achieve those ends. I'm not clear on whether I'm even remotely doing the right things with my construcor and my get/set accessors (as I don't want the user to be choosing things like how many wheels a Car has, I haven't declared set accessors). One thing I think I've noticed is that the user would have to ask the program for the number of wheels before the motor type and that before the horsepower. I think this is because they're not calculated within the constructor, but I'm not certain.
Anyone clarity would be vastly appreciated.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace VehicleClasses
{
abstract public class Vehicle
{
protected const int smallMotor = 1;
protected const int mediumMotor = 3;
protected const int largeMotor = 5;
protected const int largerMotor = 7;
protected const int hugeMotor = 9;
protected const int wrongMotor = 9001;
public Vehicle()
{
_horsePower = (_motorType * _motorType) * 8;
}
protected int _wheelsNumber;
public int wheelsNumber
{
get
{
return _wheelsNumber;
}
}
protected int _motorType;
public int motorType
{
get
{
if (_wheelsNumber < 4)
{
_motorType = smallMotor;
}
else if (_wheelsNumber >= 4 && wheelsNumber <= 6)
{
_motorType = mediumMotor;
}
else if (_wheelsNumber > 6 && wheelsNumber < 10)
{
_motorType = largeMotor;
}
else if (_wheelsNumber >= 10 && wheelsNumber < 18)
{
_motorType = largerMotor;
}
else if (_wheelsNumber >= 18)
{
_motorType = hugeMotor;
}
else
{
_motorType = wrongMotor;
}
return _motorType;
}
}
protected int _horsePower;
public int horsePower
{
get
{
return _horsePower;
}
}
}
}
This is a common misapplication of inheritance. Subclasses should extend behavior, not just modify the values of state.
In your example, there is only one free variable, the number of wheels. Everything else is a derived trait based on that. Change the constructor of vehicle to take the number of wheels as an argument, then (if desired) you can add public static methods to the class like "CreateMotorcycle()" that create a vehicle with the correct number of wheels.
Alternate Suggested Exercise
Like I mentioned before, inheritance is useful when you want to extend behavior. For example, lets say you have an "Employee" base class. To keep things simple, lets say each Employee has one junior and one senior.
Whenever an employee wants time off, they have to ask their senior, but not every employee can approves. The request has to get passed up the chain until it reaches a "Manager", which is a derived instance.
Flipping it around, lets say the most senior employee is the owner. When he wants the company to do something, he doesn;t do it himself. He sends the command down the chain. Each layer might modify what needs to be done. For example, the owner says it needs to be done in 365 days, each manager says it has half the time he was told, and the worker completes the task.
Each "class" in these examples (Worker/Manager/Owner) behave differently when the same method is called. But having them all implement the same base class makes it easy to chain them together! this is a variant on the "Chain of Responsibility" and "Decorator" patterns.
I just need a bit of feedback regarding a problem I am trying to solve...
Here is a description of the problem :
My company sells some products for which the customer can pay over a certain period of time. The customers are classed as existing or new. In order to let the customers buy the product, we check the credit worthiness and on occasions a customer can be asked to deposit a bond, which is refundable. Some customers have a good payment history with us, so we don't need to charge them a bond amount. In order to implement the assessment, I have designed a solution as follows:
public interface ICreditAssessor
{
CreditAssessment Process();
Decimal CalculateBond(BondCalculator bc);
}
Two classes are defined which implement this interface.
public class GoodClientProcessor : ICreditAssessor{
..... methods
}
public class OtherClientProcessor : ICreditAssessor{
..... methods
}
There is a class which returns the appropriate processor depending on whether the customers have a good payment history with us or not.
Also, I have implemented a BondCalculator as follows:
public class BondCalculator
{
List<IRiskEvaluator> riskEvaluators;
public BondCalculator()
{
riskEvaluators = new List<IRiskEvaluator>();
}
public Decimal GetSuggestedBond()
{
Decimal riskAmount = 0;
foreach (IRiskEvaluator ire in riskEvaluators)
{
Decimal tempRisk = ire.EvaluateRisk();
if (tempRisk > riskAmount)
{
riskAmount = tempRisk;
}
}
return riskAmount;
}
public void SetRiskEvaluator(IRiskEvaluator re)
{
this.riskEvaluators.Add(re);
}
}
Interface IRiskEvaluator is as follows:
public interface IRiskEvaluator
{
Decimal EvaluateRisk();
}
The two classes implementing this interface are as follows:
public class FinancialRiskEvaluator : IRiskEvaluator
{
Decimal IRiskEvaluator.EvaluateRisk()
{
... calculate risk amount
}
}
and
public class ProductRiskEvaluator : IRiskEvaluator
{
Decimal IRiskEvaluator.EvaluateRisk()
{
... calculate risk amount
}
}
Now calling all this is done via a method. The relevant code is as below:
ICreditAssessor creditAssessor = CreditAssessorFactory.GetAssessor(somecriteria);
CreditAssessment assessment = creditAssessor.Process();
.
.
.
BondCalculator bc = new BondCalculator();
bc.SetRiskEvaluator(new FinancialRiskEvaluator(xmlResults));
bc.SetRiskEvaluator(new ProductRiskEvaluator(productCost));
creditCheckProcessor.CalculateBond(bc);
Is this design OK or can it be improved any further? One issue I see is that as the customers with good payment history do not need a bond, I still need to call the method CalculateBond and return 0 for the bond value. This somehow does not feel right. Can this somehow be improved upon? Any comments/suggestion are appreciated.
You could add a boolean BondRequired property to make the intent explicit, rather than depending on people to infer that "a bond of zero doesn't make much sense; the developer must have intended that result to represent no bond at all."
However, I agree with Magnum that this is already more complicated than seems necessary, so adding more members to the type may not be the best thing to do.