patterncsharpMinor
Program to model stress on furniture
Viewed 0 times
modelstressprogramfurniture
Problem
I found this question in Glassdoor and CareerCup, this is an OOP design question.
Many people claim to have solved it using different design patterns.
I think It can be solved either with bridge pattern or decorator pattern.
In the original question the base class is derived by 4 classes: 1.
Can you please say:
Which design pattern will you use? or how (don't have to use a design pattern)
Original Question:
You are on a team that is creating a program to model stress on furniture. Your task is to model the behavior of furniture under abuse such as excessive weight or application of fire.
Someone has already created a prototype with a base class
We will need to start adding other furniture like couches, beds, bookcases, and desks, and also new materials such as plastic, cloth, rubber, etc. Try to improve the class design - you are free to modify it however you wish since it is only a prototype.
the furniture becomes unusable if enough weight is applied; the algorithm depends on shape of furniture, and the location where the weight is applied
the furniture becomes unusable if it is made of wood, and fire is applied long enough; wood will change from brown to black if it is burnt (whether or not the furniture becomes unusable)
Please comment on my implementation of the decorator Pattern. And OOP design.
```
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace JobInterviewTests
{
[TestClass]
public class DecoratorPatternTest
{
[TestMethod]
public void DecoratorPatternUnitTest()
Many people claim to have solved it using different design patterns.
I think It can be solved either with bridge pattern or decorator pattern.
In the original question the base class is derived by 4 classes: 1.
WoodChair 2. WoodTable 3. MetalChair 4. MetalTableCan you please say:
Which design pattern will you use? or how (don't have to use a design pattern)
Original Question:
You are on a team that is creating a program to model stress on furniture. Your task is to model the behavior of furniture under abuse such as excessive weight or application of fire.
Someone has already created a prototype with a base class
Furniture, and four derived classes WoodChair, SteelChair, WoodTable, and SteelTable.We will need to start adding other furniture like couches, beds, bookcases, and desks, and also new materials such as plastic, cloth, rubber, etc. Try to improve the class design - you are free to modify it however you wish since it is only a prototype.
applyWeight(double x, double y, double weight, double seconds);the furniture becomes unusable if enough weight is applied; the algorithm depends on shape of furniture, and the location where the weight is applied
applyFire(double x, double y, double fireStrength, double seconds);the furniture becomes unusable if it is made of wood, and fire is applied long enough; wood will change from brown to black if it is burnt (whether or not the furniture becomes unusable)
Color getColor(); // possible values: Gray, Brown, Black, etc
FurnitureState getState(); // possible values: OK, UNUSABLEPlease comment on my implementation of the decorator Pattern. And OOP design.
```
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace JobInterviewTests
{
[TestClass]
public class DecoratorPatternTest
{
[TestMethod]
public void DecoratorPatternUnitTest()
Solution
A decorator should never BE a kind of the decorated object. In your code the
Therefore a decorator should only be used in conjunction with an interface (see Wikipedia article).
In this case I think the decorator pattern shouldn't be used. You model an essential part (the material) of a furniture out into a decorator. For me a furniture consists of a specific material and therefore should have the material as a composition.
Don't call your classes
Empty method implementations (like
I would wrap the weight and fire stress in classes. This makes the interface more readable and type-safe. This would have prevented the mistake you made in
The interview question also says that in the future there will be more furniture types and more materials. So instead of using a decorator I would model the material explicitly. I would move the Fire-Stresstest to the material because it solely depends on the material. When a material can burn it implements the interface
So here is my implementation of the test, hope it helps:
```
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FurnitureTest
{
[TestClass]
public class FurnitureTest
{
[TestMethod]
public void WoodChairBurns()
{
Furniture f = new WoodChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Brown, f.Material.Color);
f.ApplyFireStress(new FireStress { FireStrength = 10, Seconds = 20 });
Assert.AreEqual(FurnitureState.Unusable, f.FurnitureState);
Assert.AreEqual(Color.Black, f.Material.Color);
}
[TestMethod]
public void SteelChairDoesNotBurn()
{
Furniture f = new SteelChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
f.ApplyFireStress(new FireStress { FireStrength = 10, Seconds = 20 });
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
}
[TestMethod]
public void SteelChairBreaksUnderWeight()
{
Furniture f = new SteelChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
f.ApplyWeightStress(new WeightStress { X = 5, Y = 5, Weight = 100 });
Assert.AreEqual(FurnitureState.Unusable, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
}
}
class WeightStress
{
public double X { get; set; }
public double Y { get; set; }
public double Weight { get; set; }
}
class FireStress
{
public double FireStrength { get; set; }
public double Seconds { get; set; }
}
enum FurnitureState
{
Ok,
Unusable
}
enum Color
{
Gray,
Brown,
Black
}
interface IBurnable
{
FurnitureState ApplyFireStress(FireStress fireStress);
}
abstract class Material
{
public Color Color { get; protected set; }
protected Material(Color color)
{
Color = color;
}
}
class Wood : Material, IBurnable
{
public Wood() : base(Color.Brown)
{}
public FurnitureState ApplyFireStress(FireStress fireStress)
{
if(fireStress.FireStrength >= 10 && fireStress.Seconds >= 5)
{
Color = Color.Black;
return FurnitureState.Unusable;
}
else
{
return FurnitureState.Ok;
}
}
}
class Steel : Material
{
public Steel() : base(Color.Gray)
{ }
}
abstract class Furniture
{
public Material Material { get; private set; }
public FurnitureState FurnitureState { get; private set; }
protected Furniture(Material material)
{
Material = material;
}
public void ApplyWeightStress(WeightStress stress)
{
if(BreaksUnderWeight(stress))
{
FurnitureState = FurnitureState.Unusable;
BaseDecorator inherits from Furniture and therefore has an own state (which is Color, FurnitureState, ...). This leads to the problem that the WoodDecorator sets its own _color to black while the decorated furniture stays brown!Therefore a decorator should only be used in conjunction with an interface (see Wikipedia article).
In this case I think the decorator pattern shouldn't be used. You model an essential part (the material) of a furniture out into a decorator. For me a furniture consists of a specific material and therefore should have the material as a composition.
Don't call your classes
BaseChair, just use Chair. When you have classes like BaseChair (or better Chair) they should always be abstract because you can't instantiate a Base-Thing, you always need a concrete thing (you do that right at the beginning with Furniture temp = new BaseChair()). To prevent this automatically make the constructor protected.Empty method implementations (like
applyFire) are always a code smell.I would wrap the weight and fire stress in classes. This makes the interface more readable and type-safe. This would have prevented the mistake you made in
BaseDecorator.applyWeight where you call _furniture.applyFire.The interview question also says that in the future there will be more furniture types and more materials. So instead of using a decorator I would model the material explicitly. I would move the Fire-Stresstest to the material because it solely depends on the material. When a material can burn it implements the interface
IBurnable.So here is my implementation of the test, hope it helps:
```
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FurnitureTest
{
[TestClass]
public class FurnitureTest
{
[TestMethod]
public void WoodChairBurns()
{
Furniture f = new WoodChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Brown, f.Material.Color);
f.ApplyFireStress(new FireStress { FireStrength = 10, Seconds = 20 });
Assert.AreEqual(FurnitureState.Unusable, f.FurnitureState);
Assert.AreEqual(Color.Black, f.Material.Color);
}
[TestMethod]
public void SteelChairDoesNotBurn()
{
Furniture f = new SteelChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
f.ApplyFireStress(new FireStress { FireStrength = 10, Seconds = 20 });
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
}
[TestMethod]
public void SteelChairBreaksUnderWeight()
{
Furniture f = new SteelChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
f.ApplyWeightStress(new WeightStress { X = 5, Y = 5, Weight = 100 });
Assert.AreEqual(FurnitureState.Unusable, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
}
}
class WeightStress
{
public double X { get; set; }
public double Y { get; set; }
public double Weight { get; set; }
}
class FireStress
{
public double FireStrength { get; set; }
public double Seconds { get; set; }
}
enum FurnitureState
{
Ok,
Unusable
}
enum Color
{
Gray,
Brown,
Black
}
interface IBurnable
{
FurnitureState ApplyFireStress(FireStress fireStress);
}
abstract class Material
{
public Color Color { get; protected set; }
protected Material(Color color)
{
Color = color;
}
}
class Wood : Material, IBurnable
{
public Wood() : base(Color.Brown)
{}
public FurnitureState ApplyFireStress(FireStress fireStress)
{
if(fireStress.FireStrength >= 10 && fireStress.Seconds >= 5)
{
Color = Color.Black;
return FurnitureState.Unusable;
}
else
{
return FurnitureState.Ok;
}
}
}
class Steel : Material
{
public Steel() : base(Color.Gray)
{ }
}
abstract class Furniture
{
public Material Material { get; private set; }
public FurnitureState FurnitureState { get; private set; }
protected Furniture(Material material)
{
Material = material;
}
public void ApplyWeightStress(WeightStress stress)
{
if(BreaksUnderWeight(stress))
{
FurnitureState = FurnitureState.Unusable;
Code Snippets
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FurnitureTest
{
[TestClass]
public class FurnitureTest
{
[TestMethod]
public void WoodChairBurns()
{
Furniture f = new WoodChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Brown, f.Material.Color);
f.ApplyFireStress(new FireStress { FireStrength = 10, Seconds = 20 });
Assert.AreEqual(FurnitureState.Unusable, f.FurnitureState);
Assert.AreEqual(Color.Black, f.Material.Color);
}
[TestMethod]
public void SteelChairDoesNotBurn()
{
Furniture f = new SteelChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
f.ApplyFireStress(new FireStress { FireStrength = 10, Seconds = 20 });
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
}
[TestMethod]
public void SteelChairBreaksUnderWeight()
{
Furniture f = new SteelChair();
Assert.AreEqual(FurnitureState.Ok, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
f.ApplyWeightStress(new WeightStress { X = 5, Y = 5, Weight = 100 });
Assert.AreEqual(FurnitureState.Unusable, f.FurnitureState);
Assert.AreEqual(Color.Gray, f.Material.Color);
}
}
class WeightStress
{
public double X { get; set; }
public double Y { get; set; }
public double Weight { get; set; }
}
class FireStress
{
public double FireStrength { get; set; }
public double Seconds { get; set; }
}
enum FurnitureState
{
Ok,
Unusable
}
enum Color
{
Gray,
Brown,
Black
}
interface IBurnable
{
FurnitureState ApplyFireStress(FireStress fireStress);
}
abstract class Material
{
public Color Color { get; protected set; }
protected Material(Color color)
{
Color = color;
}
}
class Wood : Material, IBurnable
{
public Wood() : base(Color.Brown)
{}
public FurnitureState ApplyFireStress(FireStress fireStress)
{
if(fireStress.FireStrength >= 10 && fireStress.Seconds >= 5)
{
Color = Color.Black;
return FurnitureState.Unusable;
}
else
{
return FurnitureState.Ok;
}
}
}
class Steel : Material
{
public Steel() : base(Color.Gray)
{ }
}
abstract class Furniture
{
public Material Material { get; private set; }
public FurnitureState FurnitureState { get; private set; }
protected FurniturContext
StackExchange Code Review Q#162067, answer score: 5
Revisions (0)
No revisions yet.