Discount strategy in shopping cart and orders - c#

I am trying to implement a system that can handle multiple discounts applied to my cart/completed orders. I have applied a strategy type pattern to encapsulate the processing of the discounts within the discounts.
I have come up with the following: an abstract discount base class with subclasses making up the concrete discounts. These are then applied to either an order/cart object and will process the contents of the order/cart when added to the cart/order.
Would love some comments on the code attached. Various protected constructors and members marked "virtual" needed for nhibernate.
Chev
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace CodeCollective.RaceFace.DiscountEngine
{
[TestFixture]
public class TestAll
{
#region Tests
[Test]
public void Can_Add_Items_To_Cart()
{
Cart cart = LoadCart();
// display the cart contents
foreach (LineItem lineItem in cart.LineItems)
{
Console.WriteLine("Product: {0}\t Price: {1:c}\t Quantity: {2} \t Subtotal: {4:c} \t Discount: {3:c} \t| Discounts Applied: {5}", lineItem.Product.Name, lineItem.Product.Price, lineItem.Quantity, lineItem.DiscountAmount, lineItem.Subtotal, lineItem.Discounts.Count);
}
}
[Test]
public void Can_Add_Items_To_An_Order()
{
// create the cart
Order order = new Order(new Member("Chev"));
// add items to the cart
GenericProduct hat = new GenericProduct("Cap", 110m);
order.AddLineItem(hat, 5);
EventItem race = new EventItem("Ticket", 90m);
order.AddLineItem(race, 1);
// add discounts
Discount percentageOff = new PercentageOffDiscount("10% off all items", 0.10m);
percentageOff.CanBeUsedInJuntionWithOtherDiscounts = false;
order.AddDiscount(percentageOff);
Discount spendXgetY = new SpendMoreThanXGetYDiscount("Spend more than R100 get 10% off", 100m, 0.1m);
spendXgetY.SupercedesOtherDiscounts = true;
order.AddDiscount(spendXgetY);
Discount buyXGetY = new BuyXGetYFree("Buy 4 hats get 2 hat free", new List<Product> { hat }, 4, 2);
buyXGetY.CanBeUsedInJuntionWithOtherDiscounts = false;
buyXGetY.SupercedesOtherDiscounts = true;
order.AddDiscount(buyXGetY);
// display the cart contents
foreach (LineItem lineItem in order.LineItems)
{
Console.WriteLine("Product: {0}\t Price: {1:c}\t Quantity: {2} \t Subtotal: {4:c} \t Discount: {3:c} \t| Discounts Applied: {5}", lineItem.Product.Name, lineItem.Product.Price, lineItem.Quantity, lineItem.DiscountAmount, lineItem.Subtotal, lineItem.Discounts.Count);
}
}
[Test]
public void Can_Process_A_Cart_Into_An_Order()
{
Cart cart = LoadCart();
Order order = ProcessCartToOrder(cart);
// display the cart contents
foreach (LineItem lineItem in order.LineItems)
{
Console.WriteLine("Product: {0}\t Price: {1:c}\t Quantity: {2} \t Subtotal: {4:c} \t Discount: {3:c} \t| Discounts Applied: {5}", lineItem.Product.Name, lineItem.Product.Price, lineItem.Quantity, lineItem.DiscountAmount, lineItem.Subtotal, lineItem.Discounts.Count);
}
}
private static Cart LoadCart()
{
// create the cart
Cart cart = new Cart(new Member("Chev"));
// add items to the cart
GenericProduct hat = new GenericProduct("Cap", 110m);
cart.AddLineItem(hat, 5);
EventItem race = new EventItem("Ticket", 90m);
cart.AddLineItem(race, 1);
// add discounts
Discount percentageOff = new PercentageOffDiscount("10% off all items", 0.10m);
percentageOff.CanBeUsedInJuntionWithOtherDiscounts = false;
cart.AddDiscount(percentageOff);
Discount spendXgetY = new SpendMoreThanXGetYDiscount("Spend more than R100 get 10% off", 100m, 0.1m);
spendXgetY.SupercedesOtherDiscounts = true;
cart.AddDiscount(spendXgetY);
Discount buyXGetY = new BuyXGetYFree("Buy 4 hats get 2 hat free", new List<Product> { hat }, 4, 2);
buyXGetY.CanBeUsedInJuntionWithOtherDiscounts = false;
buyXGetY.SupercedesOtherDiscounts = true;
cart.AddDiscount(buyXGetY);
return cart;
}
private static Order ProcessCartToOrder(Cart cart)
{
Order order = new Order(cart.Member);
foreach(LineItem lineItem in cart.LineItems)
{
order.AddLineItem(lineItem.Product, lineItem.Quantity);
foreach(Discount discount in lineItem.Discounts)
{
order.AddDiscount(discount);
}
}
return order;
}
#endregion
}
#region Discounts
[Serializable]
public abstract class Discount : EntityBase
{
protected internal Discount()
{
}
public Discount(string name)
{
Name = name;
}
public virtual bool CanBeUsedInJuntionWithOtherDiscounts { get; set; }
public virtual bool SupercedesOtherDiscounts { get; set; }
public abstract OrderBase ApplyDiscount();
public virtual OrderBase OrderBase { get; set; }
public virtual string Name { get; private set; }
}
[Serializable]
public class PercentageOffDiscount : Discount
{
protected internal PercentageOffDiscount()
{
}
public PercentageOffDiscount(string name, decimal discountPercentage)
: base(name)
{
DiscountPercentage = discountPercentage;
}
public override OrderBase ApplyDiscount()
{
// custom processing
foreach (LineItem lineItem in OrderBase.LineItems)
{
lineItem.DiscountAmount = lineItem.Product.Price * DiscountPercentage;
lineItem.AddDiscount(this);
}
return OrderBase;
}
public virtual decimal DiscountPercentage { get; set; }
}
[Serializable]
public class BuyXGetYFree : Discount
{
protected internal BuyXGetYFree()
{
}
public BuyXGetYFree(string name, IList<Product> applicableProducts, int x, int y)
: base(name)
{
ApplicableProducts = applicableProducts;
X = x;
Y = y;
}
public override OrderBase ApplyDiscount()
{
// custom processing
foreach (LineItem lineItem in OrderBase.LineItems)
{
if(ApplicableProducts.Contains(lineItem.Product) && lineItem.Quantity > X)
{
lineItem.DiscountAmount += ((lineItem.Quantity / X) * Y) * lineItem.Product.Price;
lineItem.AddDiscount(this);
}
}
return OrderBase;
}
public virtual IList<Product> ApplicableProducts { get; set; }
public virtual int X { get; set; }
public virtual int Y { get; set; }
}
[Serializable]
public class SpendMoreThanXGetYDiscount : Discount
{
protected internal SpendMoreThanXGetYDiscount()
{
}
public SpendMoreThanXGetYDiscount(string name, decimal threshold, decimal discountPercentage)
: base(name)
{
Threshold = threshold;
DiscountPercentage = discountPercentage;
}
public override OrderBase ApplyDiscount()
{
// if the total for the cart/order is more than x apply discount
if(OrderBase.GrossTotal > Threshold)
{
// custom processing
foreach (LineItem lineItem in OrderBase.LineItems)
{
lineItem.DiscountAmount += lineItem.Product.Price * DiscountPercentage;
lineItem.AddDiscount(this);
}
}
return OrderBase;
}
public virtual decimal Threshold { get; set; }
public virtual decimal DiscountPercentage { get; set; }
}
#endregion
#region Order
[Serializable]
public abstract class OrderBase : EntityBase
{
private IList<LineItem> _LineItems = new List<LineItem>();
private IList<Discount> _Discounts = new List<Discount>();
protected internal OrderBase() { }
protected OrderBase(Member member)
{
Member = member;
DateCreated = DateTime.Now;
}
public virtual Member Member { get; set; }
public LineItem AddLineItem(Product product, int quantity)
{
LineItem lineItem = new LineItem(this, product, quantity);
_LineItems.Add(lineItem);
return lineItem;
}
public void AddDiscount(Discount discount)
{
discount.OrderBase = this;
discount.ApplyDiscount();
_Discounts.Add(discount);
}
public virtual decimal GrossTotal
{
get
{
return LineItems
.Sum(x => x.Product.Price * x.Quantity);
}
}
public virtual DateTime DateCreated { get; private set; }
public IList<LineItem> LineItems
{
get
{
return _LineItems;
}
}
}
[Serializable]
public class Order : OrderBase
{
protected internal Order() { }
public Order(Member member)
: base(member)
{
}
}
#endregion
#region LineItems
[Serializable]
public class LineItem : EntityBase
{
private IList<Discount> _Discounts = new List<Discount>();
protected internal LineItem() { }
public LineItem(OrderBase order, Product product, int quantity)
{
Order = order;
Product = product;
Quantity = quantity;
}
public virtual void AddDiscount(Discount discount)
{
_Discounts.Add(discount);
}
public virtual OrderBase Order { get; private set; }
public virtual Product Product { get; private set; }
public virtual int Quantity { get; private set; }
public virtual decimal DiscountAmount { get; set; }
public virtual decimal Subtotal
{
get { return (Product.Price*Quantity) - DiscountAmount; }
}
public virtual IList<Discount> Discounts
{
get { return _Discounts.ToList().AsReadOnly(); }
}
}
#endregion
#region Member
[Serializable]
public class Member : EntityBase
{
protected internal Member() { }
public Member(string name)
{
Name = name;
}
public virtual string Name { get; set; }
}
#endregion
#region Cart
[Serializable]
public class Cart : OrderBase
{
protected internal Cart()
{
}
public Cart(Member member)
: base(member)
{
}
}
#endregion
#region Products
[Serializable]
public abstract class Product : EntityBase
{
protected internal Product()
{
}
public Product(string name, decimal price)
{
Name = name;
Price = price;
}
public virtual string Name { get; set; }
public virtual decimal Price { get; set; }
}
// generic product used in most situations for simple products
[Serializable]
public class GenericProduct : Product
{
protected internal GenericProduct()
{
}
public GenericProduct(String name, Decimal price) : base(name, price)
{
}
}
// custom product with additional properties and methods
[Serializable]
public class EventItem : Product
{
protected internal EventItem()
{
}
public EventItem(string name, decimal price) : base(name, price)
{
}
}
#endregion
#region EntityBase
[Serializable]
public abstract class EntityBase
{
private readonly Guid _id;
protected EntityBase() : this(GenerateGuidComb())
{
}
protected EntityBase(Guid id)
{
_id = id;
}
public virtual Guid Id
{
get { return _id; }
}
private static Guid GenerateGuidComb()
{
var destinationArray = Guid.NewGuid().ToByteArray();
var time = new DateTime(0x76c, 1, 1);
var now = DateTime.Now;
var span = new TimeSpan(now.Ticks - time.Ticks);
var timeOfDay = now.TimeOfDay;
var bytes = BitConverter.GetBytes(span.Days);
var array = BitConverter.GetBytes((long)(timeOfDay.TotalMilliseconds / 3.333333));
Array.Reverse(bytes);
Array.Reverse(array);
Array.Copy(bytes, bytes.Length - 2, destinationArray, destinationArray.Length - 6, 2);
Array.Copy(array, array.Length - 4, destinationArray, destinationArray.Length - 4, 4);
return new Guid(destinationArray);
}
public virtual int Version { get; protected set; }
#region Equality Tests
public override bool Equals(object entity)
{
return entity != null
&& entity is EntityBase
&& this == (EntityBase)entity;
}
public static bool operator ==(EntityBase base1,
EntityBase base2)
{
// check for both null (cast to object or recursive loop)
if ((object)base1 == null && (object)base2 == null)
{
return true;
}
// check for either of them == to null
if ((object)base1 == null || (object)base2 == null)
{
return false;
}
if (base1.Id != base2.Id)
{
return false;
}
return true;
}
public static bool operator !=(EntityBase base1, EntityBase base2)
{
return (!(base1 == base2));
}
public override int GetHashCode()
{
{
return Id.GetHashCode();
}
}
#endregion
#endregion
}
}

As I mentioned in the comments to your question I don't think strategy is apt in this case.
To me all these discounts BuyXGetYFree, SpendMoreThanXGetYDiscount etc are all rules (and may not all neccesarily be about getting discount) that can be applied in calculating product/cart cost. I would build a RulesEngine utilising the rules you outlined and when you ask the cart to calculate its cost process it against the RulesEngine. The RulesEngine would process the product lines making up the cart and the overall order and apply the relevant adjustments to costs etc.
The RulesEngine could even control the order in which the rules are applied.
Rules could be product based (e.g. Buy one get one free) or order based (eg. Buy X items get free shipping) and you could even have expiry dates built in. These rules would be persisted to a data store.

To me the Decorator pattern seems more applicable here. It starts with the a similar Discount class hierarchy you have, but the discounts would also implement OrderBase. Then they decorate the order instead of just being attached to it. When queried, the decorator gets the order data from the order instance it decorates (which may be a plain vanilla order, or another decorator), and applies to it the appropriate discount. IMO this is fairly easy to implement but also flexible enough; in short, to me this is the simplest solution that may work.
The order of discounts in the decorator chain is probably not arbitrary though; at first guess you should apply price altering discounts first, then quantity altering ones. But I guess this is not a very strong constraint.

Related

Define material model with UnitsNet for material property storage

The goal is to build a metal database with UnitsNet with a defined pool of material properties.
These properties are to be represented in a DataGrid.
For example the PropertyDataGrid for copper:
Property
Value
Unit
Yield
40
MPa
Young modulus
70000
MPa
Density
2.6989
g/cm³
I'm not sure how to start.
First option: use an interface
using UnitsNet;
public interface IMetalProperty
{
public IQuantity Quantity { get; set; }
}
public class Density : IMetalProperty
{
public IQuantity Quantity { get; set; }
public override string ToString()
{
return Quantity.ToString();
}
}
public class Yield : IMetalProperty
{
public Pressure Quantity { get; set; }
public override string ToString()
{
return Quantity.ToString();
}
}
public class YoungModulus : IMetalProperty
{
public Pressure Value { get; set; }
public override string ToString()
{
return Quantity.ToString();
}
}
Than I can go ahead with a list or whatever:
var properties = new List<IMetalProperty>();
properties.Add(new Density { Quantity = UnitsNet.Density.FromGramsPerCubicCentimeter(2.6989) });
properties.Add(new Yield { Quantity = Pressure.FromMegapascals(40) });
Second option: use an abstract class
using UnitsNet;
public abstract class MetalProperty
{
public IQuantity Quantity { get; set; }
public override string ToString()
{
return Quantity.ToString();
}
}
public class Density : IMetalProperty
{
}
public class Yield : IMetalProperty
{
}
public class YoungModulus : IMetalProperty
{
}
The list works just as well:
var properties = new List<MetalProperty>();
properties.Add(new Density { Quantity = UnitsNet.Density.FromGramsPerCubicCentimeter(2.6989) });
properties.Add(new Yield { Quantity = Pressure.FromMegapascals(40) });
Questions:
Which is the better or the most typical way?
Is there a possibility to ensure the use of the right Units?
For example that it is restricted to add a metal property to the list: new Yield { Quantity = Pressure.FromGramsPerCubicCentimeter(40) }
How can I provide a list of all possible properties from which the user can choose one and define a new property for this metal?
Thanks for any help!

Calculate the sum of the child objects of the parent entities in the list

My list is structured like this:
public class Custo{
public int id { get; set; }
public int idParent { get; set; }
public decimal amount{ get; set; }
public decimal unitaryValue{ get; set; }
}
List<Custo> myLIst = new List<Custo>();
I want my list to return like this:
Name Total Amount Total Value
Projetos 17,00 $70
Arquitetura 15,00 $60
Estrutura 10,00 $35
Modulo 5,00 $25
Desenho 2,00 $10
Artistico 2,00 $10
Projetos Eletricos 0,00 $0
Essentially in a composite pattern you would need three classes. One would be the treenode and the other two would inherit from that. One would be a project capable of holding children. The other would be a child/leaf node and would be the individual Custos.
When you use the classes you would create a new Projectos and add child nodes, then call the Display method when you wanted them to display. You could obviously add logic for other functions. This is similar to code found here: http://www.dofactory.com/net/composite-design-pattern
Usage might be
Main
Projectos project = new Projectos("Projetos");
project.Add(new Custos("Arquitetura", 15, 70.00);
Projectos electricos = new Projectos("Electricos");
electricos.Add(new Custos("custo1", 20, 80.00);
project.Add(electricos);
project.Display();
Projectos
using System;
using System.Collections.Generic;
namespace CompositePatternExercise
{
class Projectos : CustosNode
{
private List<CustosNode> elements = new List<CustosNode>();
// Constructor
public Projectos(string name) : base(name)
{
}
public override void Add(CustosNode d)
{
elements.Add(d);
}
public override void Remove(CustosNode d)
{
elements.Remove(d);
}
public override void Display()
{
decimal totalValue = 0;
decimal totalAmount = 0;
Console.WriteLine(_name);
// Display each child element on this node
foreach (CustosNode d in elements)
{
d.Display();
totalAmount += d.Amount;
totalValue += d.Value;
}
Console.Write("Project total:" + totalAmount.ToString("C") + " " + totalAmount.ToString("C"));
}
}
}
Custos
namespace CompositePatternExercise
{
class Custos : CustosNode
{
// Constructor
public Custos(string name, decimal amount, decimal value) : base(name, amount, value)
{
}
public override void Add(CustosNode c)
{
Console.WriteLine(
"Cannot add to a custo");
}
public override void Remove(CustosNode c)
{
Console.WriteLine(
"Cannot remove from a custo");
}
public override void Display()
{
Console.WriteLine(_name + " " + Amount.ToString("C") + " " + Value.ToString("C"));
}
}
}
}
CustosNode
namespace CompositePatternExercise
{
abstract class CustosNode
{
protected string _name;
protected decimal _amount = 0m;
protected decimal _value = 0m;
public decimal Value { get => _value; }
public decimal Amount { get => _amount; }
// Constructor
public CustosNode(string name)
{
this._name = name;
}
public CustosNode(string name, decimal amount, decimal value)
{
this._name = name;
this._amount = amount;
this._value = value;
}
public abstract void Add(CustosNode c);
public abstract void Remove(CustosNode c);
public abstract void Display();
}
}

Substitude father class from child class

I have a class Father and an inherited class Child. Inside the Child's constructor I want to pass a Father class to cast all Father's properties.
This is my code
class Father
{
int prop1;
int prop2;
// many more properties;
}
class Child : Father
{
string _name;
int _age;
//etc...
public Child(string Name, int Age, Father father)
{
this._name = Name;
this._age = Age;
base = father; //<== this is what I mean to do
}
I know I can't do this directly. What is the right way?
This is complete code, some code is in spanish
class AuditRegistry : Audit
{
protected string _cud;
protected int _employee, _consecutive;
protected DateTime _date;
public string CUD { get { return _cud; } }
private int Consecutive { get { return _consecutive; } }
public DateTime Date { get { return _date; } }
public int Client { get; set; }
public int Employee { get { return _employee; } }
public float NetAmount
{
get
{
float acum = 0;
//Sum (qty * price) of products in a struct collection
}
}
public float GrossAmount
{
get
{
float acum = 0;
//Sum in acum (qty * price + tax) of each products in a struct collection
return acum;
}
}
public float Paid
{
get
{
float acum = 0;
//Sum every paid in a struct collection
return acum;
}
}
public float Change
{ get; set; }
public bool FullPaid
{
get { return (Paid != null && Paid >= NetAmount); }
}
public ArticlesCollection Products { get; set; } //struct previusly declared
public PaidsCollection Paids { get; set; } // struct previously declared
public AuditRegistry(string CUD, int Employee, int Consecutive, DateTime Date, int Client, int C, int Company, int Terminal )
{
this._cud = CUD;
this._employee = Employee;
this._consecutive = Consecutive;
this._date = Date;
this.Client = Client;
base._c = C;
base._company = Company;
base._terminal = Terminal;
}
}
class Order : AuditRegistry
{
int _consec;
public DateTime DeliveryDate { get; set; }
public int Consecutive { get { return _consec; } }
public char Modification { get; set; }
public string Code { get { return (_consec.ToString() + Modificacion); } }
public bool Entregado { get; set; }
/// <summary>
/// Constructor for load a Order from database to memory
/// </summary>
public Order(DateTime DeliveryDate, int Consecutive, char Modification, AuditRegistry Registry) // Here is the child constructor
{
this.DeliveryDate = DeliveryDate;
this._consec = Consecutive;
this.Modification = Modification;
base = AuditRegistry; //Wrong idea
}
/// <summary>
/// Constructor for new Order
/// </summary>
public Pedido(DateTime DeliveryDate, int Employee)
{
this.DeliveryDate = DeliveryDate;
this._consec = 1;
this.Modification = 'A';
base._employee = Employee;
base._date = DateTime.Now;
}
}
Semantics of a child being a father aside...
A good way is using a copy constructor:
class Father
{
int prop1;
int prop2;
// much more properties;
protected Father(Father copy)
{
prop1 = copy.prop1;
prop2 = copy.prop2;
}
}
class Child : Father
{
string _name;
int _age;
//etc...
public Child(string Name, int Age, Father father)
: base(father)
{
this._name = Name;
this._age = Age;
}
}
Its a protected constructor so only children of the parent class can call it. You use the constructor chaining base(father) to intantiate the construtor of the base class and pass the object you want to copy.
You can't assign the base object directly in code, its just a reference to the instance of the base class that the current class derives from.
There is absolutely no way to do this. A Child is a Father and you can't just swap part of the object out to another reference. The base keyword is only intended for calling base class methods explicitly.
Given that a Child is not a "type of" Father, inheritance is probably the wrong answer here anyways. You would be better off doing something like:
class Person
class Father : Person
class Child : Person
{
Father father;
}
(Pseudo-code above). Basically, prefer composition over inheritance here.

Polymorphism and Interfaces in C#

Create three small classes unrelated by inheritance—classes Building, Car and Bicycle. Write an interface ICarbonFootprint with a GetCarbonFootprint method. Have each of your classes implement that interface, so that its GetCarbonFootprint method calculates an appropriate carbon footprint for that class (check out a few websites that explain how to calculate carbon footprints). Write an app that creates objects of each of the three classes, places references to those objects in List, then iterates through the List, polymorphically invoking each object’s GetCarbonFootprint method. Constructor of Car initialize “gallon of gas”, and the Building constructor will initialize buiding-square-footage.
how to calculate carbon-footprint
One gallon of gas yields 20 pounds of CO2 for a car
Multiply the square footage by 50 for a building
None for a bicycle
My instructor's code:
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
list[i].GetCarbonFootprint();
} // end Main
}
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Miller
{
class Program
{
static void Main(string[] args)
{
Bicycle bike = new Bicycle();
Building b = new Building();
Car car = new Car();
List<ICarbonFootprint> list = new List<ICarbonFootprint>();
list.Add(bike);
list.Add(b);
list.Add(car);
int totalCarbon = 0;
foreach (var item in list)
{
totalCarbon += item.GetCarbonFootprint();
Console.WriteLine("{0} has a footprint of: {1}", item, item.GetCarbonFootprint());
}
Console.WriteLine("Total footprint is: {0}", totalCarbon);
Console.ReadKey();
}
}
public class Bicycle : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 10;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Building : ICarbonFootprint
{
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public int GetCarbonFootprint()
{
return 2000;
}
public override string ToString()
{
return string.Format("Building");
}
}
public class Car : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 1500;
}
public override string ToString()
{
return string.Format("Car");
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
}
Me integrating my instructor's code (lines 12-23 changed AKA class Program was the only thing changed):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Miller
{
class Program
{
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
list[i].GetCarbonFootprint();
} // end Main
}
public class Bicycle : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 10;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Building : ICarbonFootprint
{
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public int GetCarbonFootprint()
{
return 2000;
}
public override string ToString()
{
return string.Format("Building");
}
}
public class Car : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 1500;
}
public override string ToString()
{
return string.Format("Car");
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
}
So, replacing my code for class Program with my instructor's code, I received the following errors:
Program.cs(51,23,51,41): error CS1729: 'Miller.Building' does not contain a constructor that takes 1 arguments
Program.cs(52,23,52,34): error CS1729: 'Miller.Car' does not contain a constructor that takes 1 arguments
Now, because the last two days before Spring break were cancelled due to the weather (snow), we weren't able to discuss. My code seems to do what the directions ask, but I would like to get my instructor's code for class Program working with my code. Could someone help me with these errors possibly?
There are a few issues with your code.
First up you need to include the constructors to make the code compile.
For Building this would look like:
private int squareFootage;
public Building(int squareFootage)
{
this.squareFootage = squareFootage;
}
And for Car this would look like:
private int gasGallons;
public Car(int gasGallons)
{
this.gasGallons = gasGallons;
}
Next, you're not following the rules for calculating the carbon footprint.
They should be:
//Bicycle
public int GetCarbonFootprint()
{
return 0;
}
//Building
public int GetCarbonFootprint()
{
return 50 * squareFootage;
}
//Car
public int GetCarbonFootprint()
{
return 20 * gasGallons;
}
Finally, your instructor's code doesn't actually display any results. The code in the for loop should be changed to be Console.WriteLine(list[i].GetCarbonFootprint()); if this is a console app.
So, all up the code should look like this:
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
Console.WriteLine(list[i].GetCarbonFootprint());
}
public class Bicycle : ICarbonFootprint
{
public string Make { get; set; }
public string Model { get; set; }
public int GetCarbonFootprint()
{
return 0;
}
}
public class Building : ICarbonFootprint
{
private int squareFootage;
public Building(int squareFootage)
{
this.squareFootage = squareFootage;
}
public string Address { get; set; }
public int GetCarbonFootprint()
{
return 50 * squareFootage;
}
}
public class Car : ICarbonFootprint
{
private int gasGallons;
public Car(int gasGallons)
{
this.gasGallons = gasGallons;
}
public string Make { get; set; }
public string Model { get; set; }
public int GetCarbonFootprint()
{
return 20 * gasGallons;
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
I've opted to short-cut the property definitions rather than implement them with fields.
The output is:
0
125000
200
You should write constructors for Building and Car like next:
public Building(int MyValue)
{
...
}
and your code will work fine.
Suggestion: Car and Bicycle shares properties, and the ICarbonFootprint implementation, so you can create a base class with an abstract method. Also the GetCarbonFootprint from ICarbonFootprint interface must be type of System.Double.
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
public class Building : ICarbonFootprint
{
public int BuildingSquareFootage { get; set; }
public string Address { get; set; }
public Building(int buildingSquareFootage, string address)
{
BuildingSquareFootage = buildingSquareFootage;
Address = address;
}
public int GetCarbonFootprint()
{
return BuildingSquareFootage * 50;
}
public override string ToString()
{
return string.Format("Building");
}
}
public abstract class CarBicycleBase : ICarbonFootprint
{
public string Make { get; set; }
public string Model { get; set; }
protected CarBicycleBase(string make, string model)
{
Make = make;
Model = model;
}
public abstract int GetCarbonFootprint();
}
public class Bicycle : CarBicycleBase
{
public Bicycle(string make, string model)
: base(make, model) { }
public override int GetCarbonFootprint()
{
return 0;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Car : CarBicycleBase
{
public int GallonOfGas { get; set; }
public Car(int gallonOfGas, string make, string model)
: base(make, model)
{
GallonOfGas = gallonOfGas;
}
public override int GetCarbonFootprint()
{
return GallonOfGas * 20;
}
public override string ToString()
{
return string.Format("Car");
}
}
Example:
...
var list = new List<ICarbonFootprint>(3)
{
new Car(10, "...", "..."),
new Bicycle("...", "..."),
new Building(20, "...")
};
foreach (ICarbonFootprint item in list)
item.GetCarbonFootprint();
...
I hope it helps.

how to integrate two classes

i am working on a small app that mange flights, i have a class that build a flight details and class that build the passenger, now, i want to load the passengers onto a flight, how should i do it? do i need to build a higer class that inherit from this two class and make a list of that type of class(i dont think that wise oop ).or should i add a ticket prop in the passenger class that have the flight number, here is my code.
public class Passenger
{
public Passenger(string name, int passportNumber)
{
this.PassengerName = name;
this.PassportNumber = passportNumber;
}
private string _passengerName;
public string PassengerName
{
get { return _passengerName; }
set { _passengerName = value; }
}
private int _passportNumber;
public int PassportNumber
{
get { return _passportNumber; }
set { _passportNumber = value; }
}
}
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
{
this.FlightNumber = flightNumber;
this.FlightDestination = flightDestination;
this.PlanModel = planmodel;
}
private int _flightNumber;
public int FlightNumber
{
get { return _flightNumber; }
set { _flightNumber = value; }
}
private string _flightDestination;
public string FlightDestination
{
get { return _flightDestination; }
set { _flightDestination = value; }
}
private string _planeModel;
public string PlanModel
{
get { return _planeModel; }
set { _planeModel = value; }
}
}
static void Main(string[] args)
{
List<FlightDetails> flightList = new List<FlightDetails>();
FlightDetails a = new FlightDetails(12,"france","jumbo");///create a flight
flightList.Add(a);/// load up the flight
}
First, you can't create a class that inherits from both other classes because multiply inheritance is not allowed in C#.
You can use aggregation, something like this:
public class FlightDetails
{
// ...
}
public class Passenger
{
// ...
}
public class Flight
{
public FlightDetails { get; private set; }
public List<Passenger> Passengers { get; private set; }
public Flight(FlightDetails details)
{
FlightDetails = details;
Passengers = new List<Passenger>();
}
public AddPassenger(Passenger p)
{
// check for ticket and so on..
Passengers.Add(p);
}
}
You can read more about aggregation here: http://en.wikipedia.org/wiki/Object_composition#Aggregation
Note that in this example for simplicity i used List but actually you need to limit access to this array (because otherwise i can do something like this: Flight.Passengers.Add(p) instead of Flight.AddPassenger(p)) so good idea will be use ReadOnlyCollection as public interface to this list.
Here's a sample code that might work. A flight has one or more passengers, thus has a List of type Passenger. In real-life, a passenger can book multiple flights. If you want the reality, you'll have to change your model but for this situation it'll work:
public class Passenger
{
public Passenger(string name, int passportNumber)
{
PassengerName = name;
PassportNumber = passportNumber
}
public string PassengerName { get; set; }
public int PassportNumber { get; set; }
}
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
{
FlightNumber = flightNumber;
FlightDestination = flightDestination;
PlanModel = planmodel;
Passengers = new List<Passengers>();
}
public int FlightNumber { get; set; }
public string FlightDestination { get; set; }
public string PlanModel { get; set; }
public List<Passenger> Passengers { get; private set; }
public void AddPassenger(string name, int number)
{
int max = 2;
int passengersNumber = Passengers.Count;
if (passengersNumber < max)
{
Passengers.Add(new Passenger(name, number);
}
}
public static void Main(string[] args)
{
var flightList = new List<FlightDetails>();
var passengersList = new List<Passenger>();
//Add passenger-objects to passengers-list
var flightOne = new FlightDetails(12, "France", "Jumbo");
flightOne.Passengers = passengersList;
flightList.Add(a);
}
Here's a better solution to limit the passengers:
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
: this(flightNumber, flightDestination, planmodel, new List<Passenger>())
{
}
public FlightDetails(int flightNumber, string flightDestination, string planmodel, List<Passenger> passengers)
{
FlightNumber = flightNumber;
FlightDestination = flightDestination;
PlanModel = planmodel;
if(passengers.Count > 2)
//throw exception or error
else
_passengers = passengers;
}
private List<Passenger> _passengers = new List<Passenger>();
public int FlightNumber { get; set; }
public string FlightDestination { get; set; }
public string PlanModel { get; set; }
public IEnumerable<Passenger> Passengers { get { return _passengers; } }
public void AddPassenger(string name, int number)
{
int max = 2;
int passengersNumber = _passengers.Count;
if (passengersNumber < max)
{
_passengers.Add(new Passenger(name, number);
}
}
}
Note: this code is written without compiling. But the idea is correct normally. :)
In logical way, relation between FlightDetail to Passenger is OneToMany. One FlightDetail can have multiple Passenger which is can be written as below. FlightDetail and Passenger should be have any common inheritance hierarchy because they are don't have any common attribute or behaviour.
public class FlightDetails
{
private List<Passenger> passengerList;
public void addPassenger(Passenger p){
if(passengerList == null){
passengerList = new ArrayList<Passenger>();
}
passengerList.add(p);
}
public List<Passenger> getPassengerList(){
return passengerList;
}
//... your other detail
}
You should add a FlightDetails property to your Passenger class. That's easier than making a List with PassportNumber as index. But, it's easier to iterate FlightDetails using List, than accessing it through Passenger.
It actually depends on how you want to access and store the relations.
It might be a good idea to read about the composite pattern which actually has a nice solution for travelling between parent-child relations, even though the pattern has another purpose.

Categories