let's say two simple decorators are defined:
// decorated object
class Product : IComponent {
// properties..
// IComponent implementation
public Decimal GetCost() {
return this.SelectedQuantity * this.PricePerPiece;
}
}
// decorators
class FixedDiscountDecorator : IComponent {
IComponent component;
// IComponent implemantation
public Decimal GetCost() {
// ...
}
public FixedDiscountDecorator(IComponent product, Decimal discountPercentage) {
// ...
}
}
class BuyXGetYFreeDiscountDecorator : IComponent {
IComponent component;
// IComponent implemantation
public Decimal GetCost() {
// ...
}
// X - things to buy
// Y - things you get free
public BuyXGetYFreeDiscountDecorator(IComponent product, Int32 X, Int32 Y) {
// ...
}
}
These decorators have different constructors' signature (parameter list). I was looking for a pattern to apply to construct decorators like it could be with factory pattern. I mean I put a string and get a decorator instance.
As a result I want to simply apply a chain of decorators to a given product:
var product = new SimpleProduct {
Id = Guid.NewGuid(),
PricePerPiece = 10M,
SelectedQuantity = 10,
Title = "simple product"
};
var itemsToApplyTheDiscount = 5;
var itemsYouGetFree = 2;
var discountPercentage = 0.3M;
var discountA = new BuyXGetYFreeDecorator(product, itemsToApplyTheDiscount, itemsYouGetFree);
var discountB = new FixedDiscountDecorator(discountA, discountPercentage);
This can be resolved using IOC container or something similar. Some of the containers popped up in my head is Unity, Windsor and SimpleInjector. I will leave the IOC container to other answers since I have no experience there.
However, I really wonder why you inject a native value.
Seeing about how the class will be used, it feels weird to have an injected value like discount percentage or x buy y free item injected into the constructor.
What if the user put 10 (as percent) instead of 0.1 (as decimal) as the discount parameter? It makes ambiguity. Additionaly, if you add checks at the constructor, you give another responsibility to the class, violating SRP.
I suggest to add a DTO such as DiscountPercentValue or BuyXGetYFreeValue. Moreover, I prefer the value of discount is being set as a context or there is a repository to be injected for it. Otherwise, someday you will need factories to handle if-else business rules related to discounts.
EDIT1:
Usually I keep the constructor validation as null checks only. Other validation than that can be considered violation.
As for the repository things, I imagine some interfaces like these:
public interface IDiscountPercentageProvider{
DiscountValue Get();
}
public interface IBuyXGetYFreeValueProvider{
BuyXGetYFreeValue Get();
}
Then in your service class, you can use something like this:
class FixedDiscountDecorator : IComponent {
IComponent component;
// IComponent implemantation
IDiscountPercentageProvider discountPercentageProvider;
public Decimal GetCost() {
DiscountValue discount = discountPercentageProvider.Get();
// ...
}
public FixedDiscountDecorator(IComponent product
, IDiscountPercentageProvider discountPercentageProvider) {
// ... just null checks here
}
}
This may be complicated at first. However, it provides better API design (no ambiguity now when using decorator). Using this, you can create a DiscountValue as a class that protects its invariants, making it safer to be used in other classes.
In your example you do show a chain of decorators applied to a given product, namely:
var discountA = new BuyXGetYFreeDecorator(product, itemsToApplyTheDiscount, itemsYouGetFree);
var discountB = new FixedDiscountDecorator(discountA, discountPercentage);
Is the question, then, what are some patterns that could be used to change the state of product governed by a specified property, building from your code above? Using your example you have and limiting my scope to determining the product Cost:
public interface IComponent
{
decimal GetCost { get; set; }
}
I would create a product class representing IComponent
public class Product
{
public IComponent Price { get; set; }
}
You may have a "default" implementation in addition to the decorator classes
public class BasePrice : IComponent
{
private Decimal _cost;
public decimal GetCost //as a property maybe use Cost with get; set; in IComponent
{
get { return _cost; }
set { _cost = value; }
}
}
I like your two decorator classes which use IoC and implement variations of cost (GetCost()) from IComponent.
To this point I have not really added anything, only a base price class. What I might do next is use an abstract class and defer specific operations to subclasses, as represented in the Template Method pattern. My concrete classes would inherit from this base class. The concrete class created will depend upon the action type passed into Factory method pattern, the class referred to below as WarrantyProcessFactory.
You mentioned using app.config ... I like enums which I would use to specify the action types to be applied to product. So let's say I want to have actions tied to the product's warranty so I can process products based on this.
public enum WarrantyAction
{
RefundProduct = 0,
ReplaceProduct = 1
}
I will use a warranty request class to represent compensation requests by customers for defective products
public class WarrantyRequest
{
public WarrantyAction Action { get; set; }
public string PaymentTransactionId { get; set; }
public decimal PricePaid { get; set; }
public decimal PostageCost { get; set; }
public long ProductId { get; set; }
public decimal AmountToRefund { get; set; }
}
Finally, I could implement the abstract template method that will be overridden by concrete classes representative of the warranty action enums
public abstract class WarrantyProcessTemplate
{
protected abstract void GenerateWarrantyTransactionFor(WarrantyRequest warrantyRequest);
protected abstract void CalculateRefundFor(WarrantyRequest warrantyRequest);
public void Process(WarrantyRequest warrantyRequest)
{
GenerateWarrantyTransactionFor(warrantyRequest);
CalculateRefundFor(warrantyRequest);
}
}
The class and the first two methods are abstract and are required to be implemented by a subclass. The third method simply calls in the two abstract methods and passes a WarrantyRequest entity as an argument.
Cases in which the client wants a refund
public class RefundWarrantyProcess : WarrantyProcessTemplate
{
protected override void GenerateWarrantyTransactionFor(WarrantyRequest warrantyRequest)
{
// Code to determine terms of the warranty and devalutionAmt...
}
protected override void CalculateRefundFor(WarrantyRequest warrantyRequest)
{
WarrantyRequest.AmountToRefund = warrantyRequest.PricePaid * devalutionAmt;
}
}
Cases in which the client wants a replacement product
public class ReplaceWarrantyProcess : WarrantyProcessTemplate
{
protected override void GenerateWarrantyTransactionFor(WarrantyRequest warrantyRequest)
{
// Code to generate replacement order
}
protected override void CalculateRefundFor(WarrantyRequest warrantyRequest)
{
WarrantyRequest.AmountToRefund = warrantyRequest.PostageCost;
}
}
public static class WarrantyProcessFactory
{
public static WarrantyProcessTemplate CreateFrom(WarrantyAction warrantyAction)
{
switch (warrantyAction)
{
case (WarrantyAction.RefundProduct):
return new RefundWarrantyProcess();
case (WarrantyAction.ReplaceProduct):
return new ReplaceWarrantyProcess();
default:
throw new ApplicationException(
"No Process Template defined for Warranty Action of " +
warrantyAction.ToString());
}
}
}
Another pattern I would consider is the Strategy Method pattern. In this case a Context class defers all calculations to a "ConcreteStrategy" referenced by its abstract class or interface. I found Scott Millet's book "Professional ASP.NET Design Patterns" as a useful resource and often return to it.
I am open to comments and criticism.
Related
Sorry if the title doesn't explain the question very well, but I couldn't think any better name. This might end up being a quite long question, but please bear with me.
Let's say I have two types of vehicles Car and Yacht which extend an interface called IVehicle.
The interface itself doesn't matter much for this question, but the classes contain properties describing them.
I then have a ITaxCalculator<T> where T : IVehicle which contains method double Calculate(T vehicle);.
There are then several classes which implement different versions of ITaxCalculator<T> (and take different constructor arguments), such as:
LegitYachtTaxCalculator : ITaxCalculator<Yacht>
TaxHavenYachtTaxCalculator : ITaxCalculator<Yacht>
CarTaxCalculator : ITaxCalculator<Car>
I then have a List<IVehicle> containing my multiple cars and yachts, and I want to calculate the total amount of taxes I'm going to have to pay for them while at the same time being able to switch out the method used to calculate each type's taxes.
Here's some code:
Interfaces:
ITaxCalculator<T>
public interface ITaxCalculator<T> where T : IVehicle
{
double Calculate(T vehicle);
}
IVehicle
public interface IVehicle
{
string RegistrationPlate { get; }
}
Implementations
Car
public class Car : IVehicle
{
public Car(string registrationPlate)
{
RegistrationPlate = registrationPlate;
}
public string RegistrationPlate { get; }
}
Yacht
public class Yacht : IVehicle
{
public int WeightInTons { get; }
public Yacht(string registrationPlate, int weightInTons)
{
RegistrationPlate = registrationPlate;
WeightInTons = weightInTons;
}
public string RegistrationPlate { get; }
}
CarTaxCalculator : ITaxCalculator<Car>
public class CarTaxCalculator : ITaxCalculator<Car>
{
public double Calculate(Car vehicle)
{
Console.WriteLine($"Calculating tax for {vehicle.GetType().FullName} with plate {vehicle.RegistrationPlate} using {this.GetType().FullName}");
return 4999.95;
}
}
LegitYachtTaxCalculator : ITaxCalculator<Yacht>
public class LegitYachtTaxCalculator : ITaxCalculator<Yacht>
{
public double WeightMultiplier { get; }
public LegitYachtTaxCalculator(double weightMultiplier)
{
WeightMultiplier = weightMultiplier;
}
public double Calculate(Yacht vehicle)
{
Console.WriteLine($"Calculating tax for {vehicle.GetType().FullName} with plate {vehicle.RegistrationPlate} using {this.GetType().FullName}");
return vehicle.WeightInTons * WeightMultiplier;
}
}
TaxHavenYachtTaxCalculator : ITaxCalculator<Yacht>
public class TaxHavenYachtTaxCalculator : ITaxCalculator<Yacht>
{
public double Calculate(Yacht vehicle)
{
Console.WriteLine($"Calculating tax for {vehicle.GetType().FullName} with plate {vehicle.RegistrationPlate} using {this.GetType().FullName}");
return 0.0; // No taxes, woho!
}
}
Main
static void Main(string[] args)
{
List<IVehicle> vehicles = new List<IVehicle>
{
new Car("PLT111"),
new Yacht("PLT333", 2500)
};
double totalTaxes = 0;
foreach (var vehicle in vehicles)
{
//Here I want to use engines which are configurable earlier to calculate the taxes for the vehicles
}
}
I've tried to solve this in many ways such as
IoC containers
A much lighter "Resolver" variant where you register engines in a class containing a Dictionary<Type, object> where object is ITaxCalculators registered and resolved through methods such as
public ITaxCalculator<T> GetTaxCalculator<T>() where T : IVehicle
public void RegisterTaxCalculator<T>(ITaxCalculator<T> calculator) where T : IPosition
Passing the ITaxCalculator to every instance of T during its creation, and letting T calculate its own taxes by using it.
They all end up feeling overly complex, using bad practices or requiring too much boilerplate. So I'm wondering what the best way would be to structure this? Am I on the wrong track from the start, or is there any pattern I haven't thought about yet?
Thanks!
Basically, you need a way to define mapping between tax calculator and vehicle.
First of all, make tax calculator non-generic:
public interface ITaxCalculator
{
double Calculate(IVehicle vehicle);
}
It's much easier to discover all non-generic implementations, load them in collection, and call Calculate.
To deal with particular IVehicle implementation details, declare base class for tax calculators, and make it generic:
public abstract class TaxCalculator<T> : ITaxCalculator
where T : IVehicle
{
public double Calculate(IVehicle vehicle)
{
// this is a single place, where cast is required
return Calculate((T)vehicle);
}
protected abstract double Calculate(T vehicle);
}
Mapping task leads us to metadata.
Most of DI-containers have this feature. E.g., here are Autofac docs.
Define the metadata class:
// This is metadata class;
// It defines vehicle type to calculate the tax value
public class TaxCalculatorMetadata
{
public Type VehicleType { get; set; }
}
Register ITaxCalculator implementations:
// Every implementation of ITaxCalculator must be registered like this
builder.RegisterType<CarTaxCalculator>()
.As<ITaxCalculator>()
.WithMetadata<TaxCalculatorMetadata>(m => m.For(_ => _.VehicleType, typeof(Car)));
Now you can load all ITaxCalculator implementations, filter them somehow ("insert them into "slots""), and get particular calculator using vehicle type from "slot":
var vehicles = new List<Vehicle>
{
// ...
};
// assuming, that tax calculators were imported
// using IEnumerable<Lazy<ITaxCalculator, TaxCalculatorMetadata>>
foreach (var vehicle in vehicles)
{
var taxCalculator = taxCalculators
.First(_ => _.Metadata.VehicleType == vehicle.GetType());
Console.WriteLine(taxCalculator.Value.Calculate(vehicle));
}
I'm defining an Interface to group two different subclasses. Each class implements the inherit method but each needs different parameters to be able to work.
Here's the interface.
public interface Billable()
{
decimal Bill();
}
Here's the first class
public class HourlyEmployee : Billable
{
public decimal Bill(int hoursWorked, decimal pricePerHour) { }
}
Here's the second
public class CommissionEmployee : Billable
{
public decimal Bill(decimal commisionPercentage) { }
}
As you can see, conceptually they use the method to achieve the same, which is charging for a service. That's why I initially thought about inheritance, but it seems that's not the best approach.
What other alternatives can make the classes relate to each other?
This doesn't directly answer the question in your title, but you did ask for other alternatives...
Your interface is a contract, guaranteeing that your classes will have a Bill() function that returns a decimal. But that doesn't mean you have to accept the parameters in that method.
Here the constructors for each class accept the parameters. The Bill() method does the calculation to return the appropriate value.
public interface IBillable
{
decimal Bill();
}
public class HourlyEmployee : IBillable
{
private int hoursWorked;
private decimal pricePerHour;
public HourlyEmployee(int hoursWorked, decimal pricePerHour)
{
this.hoursWorked = hoursWorked;
this.pricePerHour = pricePerHour;
}
public decimal Bill()
{
return hoursWorked * pricePerHour;
}
}
public class CommissionEmployee : IBillable
{
private int commissionPercentage;
public CommissionEmployee(int commissionPercentage)
{
this.commissionPercentage = commissionPercentage;
}
public decimal Bill()
{
// do some calculation using commissionPercentage and return a value...
}
}
Not sure if this is the best approach, but I think your approach of using an interface is good (which I'd call IBillable by convention).
But you should not try to accommodate all the required values for the calculation as parameters in the interface method, as this limits your extensibility, what if you come across a new kind of employee who needs one more value for bill calculation. Interface is a contract which should not change, hopefully ever. Method suggested below doesn't have that problem.
One suggestion is to use another class (let's say BillCalculator) and move the different parameters required by the Billable interface to properties of that class.
public abstract class BillCalculator: IBillable
{
abstract decimal Bill();
}
public class HourlyBillCalculator: BillCalculator
{
public int HoursWorked { get; set; }
public decimal PricePerHour { get; set; }
public HourlyBillCalculator(int hoursWorked, decimal pricePerHour)
{
HoursWorked = hoursWorked;
PricePerHour = pricePerHour;
}
public override Bill()
{
// Calculate the Bill
}
}
public class CommisionBillCalculator: BillCalculator {
public decimal CommisionRate { get; set; }
public CommisionBillCalculator(decimal rate)
{
CommisionRate = rate;
}
public override Bill() {
// Calculate the Bill
}
}
Corresponding Calculator class has to be instantiated using a factory pattern or something to fit the need. Then it's just a matter of calling the Bill method, which will use the instance properties to calculate the value.
That will let you keep interface signature consistent.
Note: Syntax may be off, but hope you get the idea.
Obviously what you propose produces a syntax error as every implementation of the interface should implement all its prototyped methods. By definition, implementing a prototype means having the same parameters, that's why you cannot have multiple parameters for the same method. However, you can take the advantage of the optional parameters introduced in .NET 4.0
So you can have something like this.
This thread, Decorator pattern implementation, has an implementation of a decorator using abstract classes. I don't like it for the simple fact that a CondimentDecorator is NOT a Beverage in the implementation given there. I'd use interfaces instead. Aren't abstract classes better for is-a relationships, and interfaces better for has-a relationships?
public interface IBeverage
{
// get a description of the beverage
String Description { get; }
// calculate cost of the beverage
double Cost { get; }
}
// HouseBlend coffee implements IBeverage
public class HouseBlend : IBeverage
{
private string description;
public String Description
{
get { return description; }
}
private double cost;
public double Cost
{
get { return cost; }
}
// Constructor
public HouseBlend() { description = "House Blend"; cost = 0.89; }
}
// DarkRoast coffee implements IBeverage
public class DarkRoast : IBeverage
{
private string description;
public String Description
{
get { return description; }
}
private double cost;
public double Cost
{
get { return cost; }
}
// Constructor
public DarkRoast() { description = "Dark Roast"; cost = 1.10; }
}
// Mocha is a Decorator
public class Mocha
{
// Mocha has-a Beverage
private IBeverage m_beverage;
private string description;
public String Description
{
get { return description; }
}
private public double Cost
{
get { return cost; }
}
// Constructor binds the object passed to member var
public Mocha(IBeverage beverage)
{
m_beverage = beverage; // not necessary for the purpose of this example
description = m_beverage.Description + ", Mocha";
cost = 0.20 + m_beverage.Cost;
}
}
Use like this:
Mocha mhb = new Mocha(new HouseBlend()); // house blend with mocha flavor
Both base clases and interfaces are frequently used to model is-a relationships. Even an interface as simple as IDisposable can be understood as "is an object with a manually controlled lifecycle", a "disposable". The more tangible differences are in whether base implementation or data fields are allowed; and in their ability to combine multiple hierarchies.
Now, when you are implementing any pattern, you usually have enough information to see whether you need data fields or not. However, you will hardly ever be able to rule out a future need to involve the same classes in additional patterns as your software grows. From that perspective, a general preference of interfaces over abstract classes gives you more long term flexibility - whenever you have a choice.
By the nature of a Decorator, you have a choice. The components typically do not have a predefined order of how they should nest. If they did, you would use inheritance directly, instead of components. So you should prefer interfaces to compose a Decorator.
All that said, your original argument is valid as well. Decorator components (features) can be understood as is-a relationships if you like; but it is not the most natural way of looking at them.
In my current project I need to be able to have both editable and read-only versions of classes. So that when the classes are displayed in a List or PropertGrid the user is not able to edit objects they should not be allowed to.
To do this I'm following the design pattern shown in the diagram below. I start with a read-only interface (IWidget), and then create an edtiable class which implements this interface (Widget). Next I create a read-only class (ReadOnlyWidget) which simply wraps the mutable class and also implements the read only interface.
I'm following this pattern for a number of different unrelated types. But now I want to add a search function to my program, which can generate results that include any variety of types including both mutable and immutable versions. So now I want to add another set of interfaces (IItem, IMutableItem) that define properties which apply to all types. So IItem defines a set of generic immutable properties, and IMutableItem defines the same properties but editable. In the end a search will return a collection of IItems, which can then later be cast to more specific types if needed.
Yet, I'm not sure if I'm setting up the relationships to IMutable and IItem correctly. Right now I have each of the interfaces (IWidget, IDooHickey) inheriting from IItem, and then the mutable classes (Widget, DooHickey) in addition also implement IMutableItem.
Alternatively, I was also thinking I could then set IMutableItem to inherit from IItem, which would hide its read-only properties with new properties that have both get and set accessors. Then the mutable classes would implement IMutableItem, and the read-only classes would implement IItem.
I'd appreciate any suggestions or criticisms regarding any of this.
Class Diagram
Code
public interface IItem
{
string ItemName { get; }
}
public interface IMutableItem
{
string ItemName { get; set; }
}
public interface IWidget:IItem
{
void Wiggle();
}
public abstract class Widget : IWidget, IMutableItem
{
public string ItemName
{
get;
set;
}
public void Wiggle()
{
//wiggle a little
}
}
public class ReadOnlyWidget : IWidget
{
private Widget _widget;
public ReadOnlyWidget(Widget widget)
{
this._widget = widget;
}
public void Wiggle()
{
_widget.Wiggle();
}
public string ItemName
{
get {return _widget.ItemName; }
}
}
public interface IDoohickey:IItem
{
void DoSomthing();
}
public abstract class Doohickey : IDoohickey, IMutableItem
{
public void DoSomthing()
{
//work it, work it
}
public string ItemName
{
get;
set;
}
}
public class ReadOnlyDoohickey : IDoohickey
{
private Doohickey _doohicky;
public ReadOnlyDoohickey(Doohickey doohicky)
{
this._doohicky = doohicky;
}
public string ItemName
{
get { return _doohicky.ItemName; }
}
public void DoSomthing()
{
this._doohicky.DoSomthing();
}
}
Is it OK to create another object when you need a readonly copy? If so then you can use the technique in the included code. If not, I think a wrapper is probably your best bet when it comes to this.
internal class Test
{
private int _id;
public virtual int ID
{
get
{
return _id;
}
set
{
if (ReadOnly)
{
throw new InvalidOperationException("Cannot set properties on a readonly instance.");
}
}
}
private string _name;
public virtual string Name
{
get
{
return _name;
}
set
{
if (ReadOnly)
{
throw new InvalidOperationException("Cannot set properties on a readonly instance.");
}
}
}
public bool ReadOnly { get; private set; }
public Test(int id = -1, string name = null)
: this(id, name, false)
{ }
private Test(int id, string name, bool readOnly)
{
ID = id;
Name = name;
ReadOnly = readOnly;
}
public Test AsReadOnly()
{
return new Test(ID, Name, true);
}
}
I would suggest that for each main class or interface, there be three defined classes: a "readable" class, a "changeable" class, and an "immutable" class. Only the "changeable" or "immutable" classes should exist as concrete types; they should both derive from an abstract "readable" class. Code which wants to store an object secure in the knowledge that it never changes should store the "immutable" class; code that wants to edit an object should use the "changeable" class. Code which isn't going to write to something but doesn't care if it holds the same value forever can accept objects of the "readable" base type.
The readable version should include public abstract methods AsChangeable(), AsImmutable(), public virtual method AsNewChangeable(), and protected virtual method AsNewImmutable(). The "changeable" classes should define AsChangeable() to return this, and AsImmutable to return AsNewImmutable(). The "immutable" classes should define AsChangeable() to return AsNewChangeable() and AsImmutable() to return this.
The biggest difficulty with all this is that inheritance doesn't work terribly well if one tries to use class types rather than interfaces. For example, if one would like to have an EnhancedCustomer class which inherits from BasicCustomer, then ImmutableEnhancedCustomer should inherit from both ImmutableBasicCustomer and ReadableEnhancedCustomer, but .net doesn't allow such dual inheritance. One could use an interface IImmutableEnhancedCustomer rather than a class, but some people would consider an 'immutable interace' to be a bit of a smell since there's no way a module that defines an interface in such a way that outsiders can use it without also allowing outsiders to define their own implementations.
Abandon hope all ye who enter here!!!
I suspect that in the long run your code is going to be very confusing. Your class diagram suggests that all properties are editable (or not) in a given object. Or are your (I'm)mutable interfaces introducing new properties that are all immutable or not, separate from the "core"/inheriting class?
Either way I think you're going to end up with playing games with property name variations and/or hiding inherited properties
Marker Interfaces Perhaps?
Consider making all properties in your classes mutable. Then implement IMutable (I don't like the name IItem) and IImutable as a marker interfaces. That is, there is literally nothing defined in the interface body. But it allows client code to handle the objects as a IImutable reference, for example.
This implies that either (a) your client code plays nice and respects it's mutability, or (b) all your objects are wrapped by a "controller" class that enforces the given object's mutability.
Could be too late :-), but the cause "The keyword 'new' is required on property because it hides property ..." is a bug in Resharper, no problem with the compiler. See the example below:
public interface IEntityReadOnly
{
int Prop { get; }
}
public interface IEntity : IEntityReadOnly
{
int Prop { set; }
}
public class Entity : IEntity
{
public int Prop { get; set; }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var entity = new Entity();
(entity as IEntity).Prop = 2;
Assert.AreEqual(2, (entity as IEntityReadOnly).Prop);
}
}
Same for the case without interfaces. The only limitation, you can't use auto-properties
public class User
{
public User(string userName)
{
this.userName = userName;
}
protected string userName;
public string UserName { get { return userName; } }
}
public class UserUpdatable : User
{
public UserUpdatable()
: base(null)
{
}
public string UserName { set { userName = value; } }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var user = new UserUpdatable {UserName = "George"};
Assert.AreEqual("George", (user as User).UserName);
}
}
I have inherited the following (terrible) code and am wondering how best to refactor it.
There are large if/else clauses all over the codebase, one of which is similar to below :
public class BaseResultItem
{
public int Property1 { get; set; }
}
public class ResultItem1 : BaseResultItem
{
public int Property2 { get; set; }
}
public class ResultItem2 : BaseResultItem
{
public int Property3 { get; set; }
}
public class BaseHistoryItem
{
public int Property1 { get; set; }
}
public class HistoryItem1 : BaseHistoryItem
{
public int Property2 { get; set; }
}
public class HistoryItem2 : BaseHistoryItem
{
public int Property3 { get; set; }
}
public class HistoryBuilder
{
public BaseHistoryItem BuildHistory(BaseResultItem result)
{
BaseHistoryItem history = new BaseHistoryItem
{
Property1 = result.Property1
};
if (result is ResultItem1)
{
((HistoryItem1)history).Property2 = ((ResultItem1)result).Property2;
}
else if (result is ResultItem2)
{
((HistoryItem2)history).Property3 = ((ResultItem2)result).Property3;
}
return history;
}
}
Note that this is a simplified example and there are many more classes involved in the actual code. There are similar if/else clauses all over the place.
I have been looking at the abstract factory pattern but I am having some problems.
Basically I am assuming that to avoid the if/else problems I need to pass the actual dervied types around. So BuildHistory should not use base types and maybe there should be multiple methods, one per derived type?
If you can't change the DTO classes perhaps you can try to subclass HistoryBuilder to deal with the different subclasses. Then you use the appropriate HistoryBuilderX to create a HistoryItem from a ResultItem. Then the question is how to get the appropriate HistoryBuilderX for the ResultItem supplied.
Still, if you can't change the BaseResultItem class to include a GetBuilder function you need to use some if..else if.. construct that inspects the classtypes of your ResultItems.
Or you create a Registry where every ResultItem class is registered with its corresponding HistoryBuilderX class. But that might be overkill.
The general 'design pattern' is simply to use object orientation with polymorphism instead of type checks. Thus: a BuildHistory method inside BaseResultItem, overridden by descendants.
Any code which checks the concrete type of an object smells (in a refactoring sense). Supporting different behaviours for different types is what OO is about.
Use polymorphism to remove the type checks.
if (result is ResultItem1)
{
((HistoryItem1)history).Property2 = ((ResultItem1)result).Property2;
}
Becomes then something like
result.addToHistory( history );
If for some reason, you don't want to scatter the logic in the item classes, have a look at the visitor pattern. In this case, you have something like:
public class Visitor {
History history;
public visit ( ResultItem1 item ) { ... }
public visit ( ResultItem2 item ) { ... }
...
}
public class ResultItem1 {
public accept( Visitor v ) { v.visit( this ); }
}
The typecheck is removed by the double-dispatch in the visitor, which is slightly more elegant.
I didn't understood exactly how the various kind of history relates to the various kind of items. So this is just a sketch of possibles direction to follow.