Reputation: 1091
I have the requirement to be able to perform many conversions of external models to my own internal models.
I have decided to apply the Adapter pattern, but I want to make it as generic as possible. So effectively, I want it to be handle both "single" POCO's, but if i need to pass/adapt a collection then this also must work eg:
IEnumerable<IAdaptee> OR IList<TAdaptee>
and return my own adapted object(s):
IEnumerable<IAdapted> OR IList<TAdapted>
I want to do something like the following:
public interface IGenericAdapter
{
TAdapted Adapt<TAdapted,TAdaptee>(TAdaptee adaptee);
}
Where I am coming unstuck is when I build my "Adapter" class, and then implement the above interface, I am getting constraint mismatch errors. This of course, makes sense, because If i am applying constraints to the classes which implement the interface, and the interface doesn't have them, then of course errors occur.
So:
public class AToBAdapter
{
public TAdapted Adapt<TAdapted,TAdaptee>(TAdaptee adaptee)
where TAdapted: IList<FooAdapted>
where TAdaptee: IList<FooAdaptee>
{
// I want my constraints to be active here, as I need to perform specific operations here
}
}
The above works fine in and of itself, which is fine. But I want to hide all this behind a generic interface that I can use whenever it suits.
Of course, Once i add this it fails due to no constraints on the interface, yet constraints on the implementing class.
public class AToBAdapter:IAdapterGeneric
What's the magic bullet here which will enable me to build a truly generic Adapter - I'm guessing certain constraints on the interface? casting? but need assistance on the best course of action.
Thanks, Chud
Upvotes: 0
Views: 90
Reputation: 1603
consider the following example :
interface IDog
{
void Bark();
}
interface ICat
{
void Meow();
}
class SomeDog : IDog
{
public void Bark()
{
Console.WriteLine(@"bark bark");
}
}
class SomeCat : ICat
{
public void Meow()
{
Console.WriteLine(@"meow meow");
}
}
class CatToDogAdapter : IDog
{
private ICat cat;
public CatToDogAdapter(ICat cat)
{
this.cat = cat;
}
public void Bark()
{
cat.Meow();
}
}
new Dog().Bark(); // bark bark
new CatToDogAdapter().Bark();// meow meow
this is how adapter works.
Let say you have a model MyAdaptedData and you recive data containing HotelName, Name,PropertyName from agoda , booking and tripadviser for each booking model you need to write adapter
AgodaAdapter : MyAdaptedData{
public AgodaAdapter(AgodaModel agodaModel){
....
}
public stirng HotelName{
get{
return agodaModel.HotelNamebyAgoda;
}
}
....
}
Same for booking and tripadvisor. Adapter pattern helps you to retrieve necessary data from external models.
Then you need to create specific adapter depending on the adaptee type. Use Factory method pattern
MyAdaptedData AdaptersFactory(object adaptee){
if(adaptee is AgodaModel)
return new AgodaAdapter(adaptee);
....
if(adaptee is XBookingModel)
return new XBookingAdapter(adaptee);
}
Upvotes: 0
Reputation: 446
If you have access to your external models, you could use an interface as a marker:
public interface IAdaptee { }
public interface IAdapted { }
And use those interfaces as your adapter interface constraints:
public interface IGenericAdapter<out TAdapted, in TAdaptee>
where TAdaptee : IAdaptee
where TAdapted : IAdapted
{
TAdapted Adapt(TAdaptee adaptee);
}
You could pass this adapter into a helper method for adapting multiple objects (assuming the adapt logic stays the same for multiple):
public IEnumerable<TAdapted> AdaptMultiple<TAdapted, TAdaptee>
(IEnumerable<TAdaptee> adaptees, IGenericAdapter<TAdapted, TAdaptee> adapter)
where TAdaptee : IAdaptee
where TAdapted : IAdapted
{
return adaptees.Select(adapter.Adapt);
}
For example, we can construct the following concrete classes:
public class ConcreteAdaptee : IAdaptee { }
public class ConcreteAdapted : IAdapted { }
public class ConcreteAdapter : IGenericAdapter<ConcreteAdapted, ConcreteAdaptee>
{
public ConcreteAdapted Adapt(ConcreteAdaptee adaptee)
{
// Adapt Logic
return new ConcreteAdapted();
}
}
And adapt them as such:
IGenericAdapter<ConcreteAdapted, ConcreteAdaptee> adapter = new ConcreteAdapter();
var adaptee = new ConcreteAdaptee();
var adapted = adapter.Adapt(adaptee);
var adaptees = new List<ConcreteAdaptee>();
var adapteds = AdaptMultiple(adaptees, adapter);
Upvotes: 1