I am modelling a program that simulates driving and refueling cars and trucks. So this is what I have done so far:
public abstract class Vehicle
{
protected Vehicle(double fuelQuantity, double fuelConsumption)
{
this.FuelQuantity = fuelQuantity;
this.FuelConsumption = fuelConsumption;
}
public double FuelQuantity { get; protected set; }
public double FuelConsumption { get; protected set; }
public abstract string Drive(double distance);
public abstract void Refuel(double liters);
}
public class Car : Vehicle
{
public Car(double fuelQuantity, double fuelConsumption) : base (fuelQuantity, fuelConsumption)
{
}
public override string Drive(double distance)
{
}
public override void Refuel(double liters)
{
}
}
So, I want to increase the value of the fuel consumption of the cars with 0.9 liters (it's summer, so cars use air conditioners). Where this can be done? I don't want to do it in the constructor because I don't think it's okay.
This would be a good place to add a decorator.
Some pseudo code (not complete!) but hopefully you get the idea.
public class VehicleDecorator : Vehicle
public VehicleDecorator(Vehicle vehicle)
{
this.vehicle = vehicle;
}
public class VehicleWithAc : VehicleDecorator
public VehicleWithAc(Vehicle vehicle) : base(vehicle){}
public override double FuelConsumption {
get{
return base.FuelConsumption+0.9 } }
Then in your program, create your car and decorate it with a VehicleWithAc decorator
Program
var baseCar = new Car();
var summerDriver = new VehicleWithAc(baseCar)
I think the problem you have is that you're passing fuelConsumption as a single variable in to the constructor, thereby stating
This is the fuel consumption of the car, full stop.
As you've found out, working through the problem - fuel consumption isn't a static thing, it's dependant on other variables, such as whether the AC is on. Doug was getting close with his mention of the decorator, but I think it can be a little simpler, but more flexible.
I think you should still pass a fuel consumption figure in, and for simplicitys sake, we'll call it baseFuelConsumption. Remember, vehicles are usually graded on urban, and highway fuel consumptions as they are generally different, but for the purposes of this, we'll ignore it.
Leaving out distance travelled etc, we have:
public abstract class Vehicle
{
private readonly double _baseFuelConsumption;
protected double BaseFuelConsumption => _baseFuelConsumption;
protected Vehicle(double baseFuelConsumption) => _baseFuelConsumption = baseFuelConsumption;
public virtual double ActualFuelConsumption => BaseFuelConsumption;
}
So, how much extra fuel consumption does an AC use? Let's take Doug's answer as a base-point, and give that to our car....
public class Car : Vehicle
{
private const double _ACModifier = 0.9;
public Car()
:base(1)
{
}
public bool IsACOn { get; set; }
public override double ActualFuelConsumption
{
get
{
double consumption = base.ActualFuelConsumption;
consumption += IsACOn ? _ACModifier : 0;
return consumption;
}
}
}
Now, for the purposes of your simulation you can switch the AC on and off, over time, and measure the ActualFuelConsumption property over time.
If you want to use this stracture you have to set custom rules for properties.
public abstract class Vehicle
{
protected Vehicle(double fuelQuantity, double fuelConsumption)
{
this.FuelQuantity = fuelQuantity;
this._fuelConsumption = fuelConsumption;
this.FuelConsumption = fuelConsumption;
}
public double FuelQuantity { get; protected set; }
private double _fuelConsumption { get; set; }
public double FuelConsumption {
get { return _fuelConsumption; }
protected set {
_fuelConsumption = (_fuelConsumption + 0.9);
} }
public abstract string Drive(double distance);
public abstract void Refuel(double liters);
}
Because your class is abstract and you dont have no overridable in properties in your derived class you cant have access to base properties.You can use condition in set for example
public double FuelConsumption {
get { return _fuelConsumption; }
protected set {
if(Issummer)
{
_fuelConsumption = (_fuelConsumption + 0.9);
}else{ _fuelConsumption =_fuelConsumption;}
} }
Related
I have trouble with figuring out how can I use generic types to solve my problem.
Also I don't know how to describe my problem in short so I will make simplified version of my problem as extended exmplanation.
I am making system for switching quality, transitioning quality levels between different types of 'component' class.
I have base class like:
public abstract class QualityLevel_Base
{
public bool Enabled = true;
public virtual void Transition(QualityLevel_Base a, QualityLevel_Base b, double value)
{
if (value >= 1) Enabled = b.Enabled; else if (value <= 0) Enabled = a.Enabled;
}
protected static double Lerp(double a, double b, double t) { return (1 - t) * a + t * b; }
}
Then I inherit from it like:
public sealed class QualityLevel_LightSource : QualityLevel_Base
{
public double Intensity;
public double Range;
public int ShadowsQuality;
public override void Transition(QualityLevel_Base a, QualityLevel_Base b, double value)
{
QualityLevel_LightSource la = a as QualityLevel_LightSource; // One part of my problem - avoid casting
QualityLevel_LightSource lb = b as QualityLevel_LightSource;
base.Transition(a, b, value);
Intensity = Lerp(la.Intensity, lb.Intensity, value);
/* etc... */
}
}
Then I want to manage quality levels in other class and be able to apply settings onto desired component class.
So I have base class to manage any count of quality levels:
public abstract class QualityManager_Base
{
public Component SourceComponent { get; protected set; }
public List<QualityLevel_Base> QualityLevels { get; protected set; }
public virtual void Initialize(Component component, int qualityLevelsCount)
{
QualityLevels = new List<QualityLevel_Base>();
SourceComponent = component;
AutoQualitySettings(qualityLevelsCount);
}
public virtual void AutoQualitySettings(int qualityLevelsCount) { }
public virtual void ApplyQualitySettings(QualityLevel_Base qualityLevel)
{
SourceComponent.Enabled = qualityLevel.Enabled;
}
}
And I inheriting it for LightSource like:
public sealed class QualityManager_LightSource : QualityManager_Base
{
public LightSource Light { get; private set; }
public override void Initialize(Component component, int qualityLevelsCount)
{
LightSource light = component as LightSource; // Another situation when I would like to avoid casting
Light = light;
base.Initialize(light, qualityLevelsCount);
}
public override void AutoQualitySettings(int qualityLevelsCount)
{
for (int i = 0; i < qualityLevelsCount; i++)
{
QualityLevel_LightSource lightSettings = new QualityLevel_LightSource();
lightSettings.Intensity = Light.Intensity;
lightSettings.Range = Light.Range;
lightSettings.ShadowsQuality = i / qualityLevelsCount;
if (i == qualityLevelsCount - 1) lightSettings.Enabled = false;
}
}
public override void ApplyQualitySettings(QualityLevel_Base qualityLevel)
{
base.ApplyQualitySettings(qualityLevel);
// To my Question: I want to use generic type to avoid casting
QualityLevel_LightSource lightSettings = qualityLevel as QualityLevel_LightSource;
Light.Intensity = lightSettings.Intensity;
Light.Range = lightSettings.Range;
Light.ShadowsQuality = lightSettings.ShadowsQuality;
}
}
Actually I managed to use generic types on this problem making stuff like:
public abstract class QualityLevel_Base<T> where T : QualityLevel_Base<T> { /*...*/ }
public class QualityLevel_LightSource : QualityLevel_Base<QualityLevel_LightSource> { /*...*/ }
public abstract class QualityManager_Base
{
public List<QualityLevel_Base> QualityLevels; // Would like to define it like that but I have to do it
// like that:
public abstract class QualityManager_Base<T> where T : QualityLevel_Base<T>
{
public List<QualityLevel_Base<T>> QualityLevels;
}
Then doing something like this causes error:
public abstract class QualityManager_Base<T> where T : QualityLevel_Base<T>
{
public List<QualityLevel_Base<T>> QualityLevels;
public virtual void AddComponentForQualityManager(Component comp)
{
if (QualityLevels == null) QualityLevels = new List<QualityLevel_Base<T>>();
LightSource light = comp as LightSource;
if (light != null)
{
QualityManager_LightSource lightManager = new QualityManager_LightSource();
QualityLevels.Add(lightManager); // Then I Can't do this because: "cannot convert from 'QualityManager_LightSource' to 'QualityLevel_Base<T>' "
}
/* ... */
}
}
"cannot convert from 'QualityManager_LightSource' to 'QualityLevel_Base'"
There is of course more going on in my system, it is just very simplified version to define my question: How can I avoid casting classes, how can I do it correctly?
Thanks!
I have some things to clarify for myself, so please bear with me.
Let's say I want to have an object that will explode after a certain period of time. If the object explodes while the person is still holding it, you get killed.
Let's consider the following implementation:
public interface IKillable
{
void Kill();
}
public interface IExplodable : IKillable
{
float TimeLeft { get; set; }
void Timer(float timeToExplode);
}
public abstract class Bomb: IExplodable
{
public float TimeLeft { get; set; }
public void Kill()
{
//Destroy the object
}
public void Timer(float timeLeft)
{
if (TimeLeft <= 0) {
Kill();
}
}
}
What if I also want to add let's say a "Backpack" instead of "Bomb" that will have the exact same functionality or any other item that can explode (and kill)?
Is inheriting a "Backpack from Bomb" reasonable in this case?
Probably copying the code won't follow SOLID principles?
Having a base class that provides common functionality for objects is both common and recommended in Unity.
Instead of calling the class Bomb, call it something more generic, like ExplodableDevice (as #zmbq answered). I would, however, make it more explicit that the device explods due to a timer, so perhaps TimerExplodableDevice. Notice that the base class should inherit from MonoBehaviour as otherwise you wouldn't be able to use those objects fully (as c# doesn't allow multiple inheritance).
An example of such implementation would be:
public interface IKillable
{
void Kill();
}
public interface IExplodable : IKillable
{
float TimeLeft { get; set; }
void Timer(float timeToExplode);
}
public abstract class TimerExplodableDevice: MonoBehaviour, IExplodable
{
public float TimeLeft { get; set; }
public virtual void Kill()
{
//Destroy the object
}
public virtual void Timer(float timeLeft)
{
if (TimeLeft <= 0)
{
Kill();
}
}
}
// this should be in a "Devices" folder, or otherwise be called appropriately
public class Backpack : TimerExplodableDevice
{
void Start()
{
TimeLeft = 100;
}
}
// this should be in a "Devices" folder, or otherwise be called appropriately
public class Bomb : TimerExplodableDevice
{
void Start()
{
TimeLeft = 10;
}
}
You can create an abstract ExplodableDevice class and have Bomb and Backpack inherit from it.
Suppose I have a Customer class. A customer can have multiple kinds of loyalty points. For one promotion, the customer may be collecting Rewards. In another, the customer may be collecting Miles. And there is no fixed number of kinds of loyalty points that the Customer is built for. I am sure this is a common use case. Is the decorator pattern a good fit given below sample code?
public interface ICustomer
{
void Display();
}
public class SimpleCustomer : ICustomer
{
public void Display()
{
Console.WriteLine("I am simple customer");
}
}
public abstract class CustomerDecorator : ICustomer
{
protected ICustomer customer;
public CustomerDecorator(ICustomer customer)
{
this.customer = customer ?? throw new ArgumentNullException("customer");
}
public abstract void Display();
}
public class RewardsDecorator : CustomerDecorator
{
private int rewards;
public RewardsDecorator(ICustomer customer, int rewards) : base(customer)
{
this.rewards = rewards;
}
public override void Display()
{
Console.WriteLine("Now I have " + rewards.ToString() + " rewards");
}
}
public class MilesDecorator : CustomerDecorator
{
private int miles;
public MilesDecorator(ICustomer customer, int miles) : base(customer)
{
this.miles = miles;
}
public override void Display()
{
Console.WriteLine("Now I have " + miles.ToString() + " miles");
}
}
Don't think Decorator pattern does what you want it to do. Decorator adds new functionalities on top of the original class. A typical wiki example would say, we can add scroll bar, menu bar, overlays and other UI components on top of canvas. So to make a proper browser window, so you will have:
public class Canvas
public class ScrollableCanvas
public class OverlayedCanvas
etc.
So that we add more functionalities to the original Canvas.
To solve your problem, you should have something like:
public abstract class LoyaltyProgramAccount {...}
public class RewardAccount extends LoyaltyProgramAccount {...}
public class MilesAccount extends LoyaltyProgramAccount {...}
And then add a registery-ish enum:
public enum LoyaltyProgramTypes {
miles,
reward,
}
and then let user be:
public class Customer {
private List<LoyaltyProgramTypes, LoyaltyProgramAccount> accounts;
public void openAccount(LoyaltyProgramTypes type, LoyaltyProgramAccount account) {
accounts.put(type, account);
}
...
}
I do not think that Decorator is the pattern you are looking for.
Besides, your code does not seem to be an implementation of the Decorator pattern. You do not add any functionality to the only function. You just override it. But adding to the existing function is what the Decorator pattern is all about.
My approach would be state / strategy pattern. There are different kinds of rewards. And a customer has one or more of them. These rewards may share a common interface and provide different implementations. The customer (or a subclass or compound object RewardedCustomer) should hold a list or map of these rewards.
I would use the visitor pattern, this is pretty ideal for your situation. This will allow you nicely separate the rewards calculations for you different customer types and run operations against all supported rewards types.
class Program
{
static void Main(string[] args)
{
MilesCustomer customer = new MilesCustomer();
ICustomerVisitor<int> visitor = new MilesCalculation(10);
var miles = customer.Visit(visitor);
visitor = new RewardsCalucation(100);
var rewards = customer.Visit(visitor);
}
}
public interface ICustomerVisitor<T>
{
T Visit(SimpleCustomer cusomter);
T Visit(RewardsCustomer cusomter);
T Visit(MilesCustomer cusomter);
}
public abstract class Customer
{
public Customer()
{
TotalMoneySpent = 10;
}
public int TotalMoneySpent { get; private set; }
public abstract T Visit<T>(ICustomerVisitor<T> visitor);
public virtual void Display()
{
Console.WriteLine("I am simple customer");
}
}
public class RewardsCalucation : ICustomerVisitor<int>
{
private int _rewardsPerDollar;
public RewardsCalucation(int rewardsPerDollar) => _rewardsPerDollar = rewardsPerDollar;
public int Visit(SimpleCustomer cusomter)
{
return 0;
}
public int Visit(RewardsCustomer cusomter)
{
return cusomter.TotalMoneySpent * _rewardsPerDollar;
}
public int Visit(MilesCustomer cusomter)
{
return 0;
}
}
public class MilesCalculation : ICustomerVisitor<int>
{
private int _milesPerDollar;
public MilesCalculation(int milesPerDollar) => _milesPerDollar = milesPerDollar;
public int Visit(SimpleCustomer cusomter)
{
return 0;
}
public int Visit(RewardsCustomer cusomter)
{
return 0;
}
public int Visit(MilesCustomer cusomter)
{
return cusomter.TotalMoneySpent * _milesPerDollar;
}
}
public class SimpleCustomer : Customer
{
public override T Visit<T>(ICustomerVisitor<T> visitor)
{
return visitor.Visit(this);
}
}
public class RewardsCustomer : Customer
{
public override T Visit<T>(ICustomerVisitor<T> visitor)
{
return visitor.Visit(this);
}
}
public class MilesCustomer : Customer
{
public override T Visit<T>(ICustomerVisitor<T> visitor)
{
return visitor.Visit(this);
}
}
Any thoughts on why altitude is not 5 at the end of this program?
So I have a Penguin class deriving from Birds, and in Birds class I have a check on whether the birds is flightless, and based on that I reset the given altitude to 0 or keep the provided altitude.
Supposing penguins can fly (isFlightless=false), Penguin.ArrangeBirdInPatterns(p); should trigger the ArrangeBirdInTheSky, which it does, and then the altitude should be the one I provided (=5), not zero.
My VS crashed and I'm using online fiddlers, hard to debug.
using System;
public class Bird {
public double altitude;
public bool isFlightless;
public virtual void setLocation(double longitude, double latitude) {
}
public virtual void setAltitude(double altitude) {
this.altitude = altitude;
}
public void ArrangeBirdOnGround()
{
setAltitude(0);
}
public void ArrangeBirdInTheSky()
{
setAltitude(altitude);
}
public static void ArrangeBirdInPatterns(Bird b)
{
if(b.isFlightless)
{
b.ArrangeBirdOnGround();
}
else
{
b.ArrangeBirdInTheSky();
}
}
};
public class Penguin : Bird
{
public override void setAltitude(double altitude) {
}
}
public class Program
{
public static void Main()
{
Bird p = new Penguin();
p.setAltitude(5);
p.isFlightless = false;
Penguin.ArrangeBirdInPatterns(p);
Console.WriteLine(p.altitude); //// returns 0. why not 5
}
}
Also, why can't I call it like: ArrangeBirdInPatterns(p); if I remove static from the ArrangeBirdInPatterns definition?
You're calling Penguin's setAltitude, which does nothing.
The type of p is Bird, but the type of the value contained there is Penguin, which overrides Bird.setAltitude, so that's what gets called.
You can look into the differences between virtual, override, and new keywords for more info on the different ways to subclass.
My goal is to create a type 'GameState' that has a set amount of different states.
I want it to act almost exactly like an enum set but I want there to be more than a single integer as data.
As an example, this is what I want to do:
switch(this.gameState)
{
case(Wait):
if(elapsedTime > gameState.TimeOutTime)
//do stuff
break;
case(Play):
if(elapsedTime > gameState.TimeOutTime)
//do other stuff
break;
}
So instead of GameState just being an enumeration of integers, I want it to contain variables like TimeOutTime and other useful information about that GameState.
Is there a way of adding depth to an enumeration or am I just attacking this problem at the wrong angle?
There are already good answers (#Selman22, #Max).
But I guess they are missing an important info: You should not switch on type. Use polymorphism instead.
So, based on your example, you should use something like this:
public abstract class GameState
{
public int TimeOutTime { get; set; }
public void CheckDoStuff()
{
if (elapsedTime > gameState.TimeOutTime) DoStuff();
}
protected abstract void DoStuff();
}
public WaitState : GameState
{
protected override DoStuff()
{
// Do stuff (wait)
}
}
public PlayState : GameState
{
protected override DoStuff()
{
// Do other stuff (play)
}
}
Note: I didn't add any enum, because I don't think one is really needed in this case.
What you want is a class. You can't do that with enums, instead add a class and make the enum a property of your class.
class GameState
{
public GameStateEnum State { get; set; }
public int TimeOutTime { get; set; }
// other properties...
}
You could easliy create a class for that like:
public class GameState
{
public StateEnum State {get; set;}
public DateTime TimeOutTime {get; set;}
}
Creating a list of GameStates would be easy like:
List<GameState> gameStateList = new List<GameState>();
You can't do that with .NET enums (you can with Java though)
Assuming you elapsedTime is a DateTime, something like:
using System;
public class GameState
{
private readonly TimeOutTime _timeOutTime;
public GameState(TimeOutTime timeOutTime)
{
_timeOutTime = timeOutTime;
}
public TimeOutTime TimeOutTime { get { return _timeOutTime; } }
}
public class TimeOutTime
{
private readonly DateTime _dateTime;
public TimeOutTime(DateTime dateTime)
{
_dateTime = dateTime;
}
public static implicit operator DateTime(TimeOutTime timeOutTime)
{
return new TimeOutTime(timeOutTime);
}
public static implicit operator TimeOutTime(DateTime timeOutTime)
{
return new TimeOutTime(timeOutTime);
}
}