Vet inte om detta är dumt kanske!?
Jag har två separata domänobjekt, båda heter Order.
Ena orderobjektet är från en gammal webbutik och det andra är från en ny webbutik, därav att båda heter Order. De innehåller alltså olika medlemmar etc.
Nu behöver jag använda båda dessa orderobjekt, vad är fiffigast då:
1.
object Order = null;
if(gammal)
Order = GetGammalOrder();
else
Order = GetNyOrder();
Jag skulle vilja köra alt. 1 då det i tvåan blir en massa if-satser för att hantera de olika objekten.
Om 1:an är ett bra sätt, hur typkonverterar tillbaka objetet till sitt rätta uppbyggnad?
object Order = null;
if(gammal)
Order = (Gammal.Order)GetGammalOrder();
else
Order = (Ny.Order)GetNyOrder();
Nån som fattar vad jag är ute efter?! Fattar knappt själv! :OO
Du ska inte typkonvertera tillbaka... Det är sånt här man har interfaces till. Skapa ett interface som definierar de metoder som ska använda på båda klasserna, och låt klasserna implementera det istället. Om du istället använder en order som ett 'object' har du ju begränsade möjligheter att använda objektets (snarare Order's) egenskaper.
Vet inte om detta är dumt kanske!?
Jag har två separata domänobjekt, båda heter Order.
Ena orderobjektet är från en gammal webbutik och det andra är från en ny webbutik, därav att båda heter Order. De innehåller alltså olika medlemmar etc.
Nu behöver jag använda båda dessa orderobjekt, vad är fiffigast då:
1.
object Order = null;
if(gammal)
Order = GetGammalOrder();
else
Order = GetNyOrder();
Jag skulle vilja köra alt. 1 då det i tvåan blir en massa if-satser för att hantera de olika objekten.
Om 1:an är ett bra sätt, hur typkonverterar tillbaka objetet till sitt rätta uppbyggnad?
object Order = null;
if(gammal)
Order = (Gammal.Order)GetGammalOrder();
else
Order = (Ny.Order)GetNyOrder();
Nån som fattar vad jag är ute efter?! Fattar knappt själv! :OO
Vad skiljer dessa orderklasser från varandra? Är nya order samma som gamla fast med några nya proppar? om ja. Varför inte då låta nya order ärva gamla order. Eller kanske lägga till de nya propparna i gamla order men styra med interface vad utvecklarna skall få tillgå?
Fast vad jag är mest nyfiken på är varför en ny o gammal order? O varför den gamla ens behöver användas.
Det som skiljer dessa två order är just olika properties, det är allt (plus databasstrukturen då).
Så här är det:
Vi håller på att bygga till en faktureringstjänst till våra webbutiker. Man ska alltså kunna betala via faktura, inga konstigheter!
Vissa kunder använder den gamla webbutiken och vissa den nya. Databasstrukturen skiljer dessa butiker åt och då också domänobjekten.
Jag skulle kunna, om jag var lat, enkelt bygga unika faktureringstjänster för varje butik men då blir det ju ingen utmaning! ;)
Så därför vill jag bygga ett gemensamt klassbibliotek som funkar till båda. I web.config anger jag sedan vilken typ av butik som körs.
Det som händer sen är ett klassiskt scenario:
En besökare lägger ett antal produkter i varukorgen och går till kassan.
I kassan väljer han faktura som betalsätt.
Här kommer det nya in:
När man väljer faktura så ska en kreditkontroll köras i bakgrunden och returnera kreditvärdigheten på kunden. Detta är en extern 3-partstjänst som anropas via en webservices.
Webservicen tar emot ett egendefinierat orderbojekt (alltså ingen av mina två) så det jag behöver är att få in något av mina två orderobjekt och få ut ett tredje. Logiskt va! :)
Det kan ju hända att vi i framtiden även bygger en tredje webbutik alt. annan typ av webbsida med betallösning så jag vill att mitt klassbibliotek ska kunna ta emot alla våra olika orderobjekt och få ut det specade 3-part objektet.
Det som skiljer dessa två order är just olika properties, det är allt (plus databasstrukturen då).
Så här är det:
Vi håller på att bygga till en faktureringstjänst till våra webbutiker. Man ska alltså kunna betala via faktura, inga konstigheter!
Vissa kunder använder den gamla webbutiken och vissa den nya. Databasstrukturen skiljer dessa butiker åt och då också domänobjekten.
Jag skulle kunna, om jag var lat, enkelt bygga unika faktureringstjänster för varje butik men då blir det ju ingen utmaning! ;)
Så därför vill jag bygga ett gemensamt klassbibliotek som funkar till båda. I web.config anger jag sedan vilken typ av butik som körs.
Det som händer sen är ett klassiskt scenario:
En besökare lägger ett antal produkter i varukorgen och går till kassan.
I kassan väljer han faktura som betalsätt.
Här kommer det nya in:
När man väljer faktura så ska en kreditkontroll köras i bakgrunden och returnera kreditvärdigheten på kunden. Detta är en extern 3-partstjänst som anropas via en webservices.
Webservicen tar emot ett egendefinierat orderbojekt (alltså ingen av mina två) så det jag behöver är att få in något av mina två orderobjekt och få ut ett tredje. Logiskt va! :)
Det kan ju hända att vi i framtiden även bygger en tredje webbutik alt. annan typ av webbsida med betallösning så jag vill att mitt klassbibliotek ska kunna ta emot alla våra olika orderobjekt och få ut det specade 3-part objektet.
Blev ni nå klokare! :)
Jag skulle nog byggt en faktureringsmodul som alla delade på.
Men sedan ett mappningslager innan och kanske efter?
mappningslagret mappar mina old objekcts till mina nya objects som faktureringsmodulen nyttjar. Om objekten sedan måste tillbaka till webbbutiken skre samma mappning fast tillbaka till the old objects. Är du med?
Mappningen kan göras antingen på hårdkodad väg dvs manuell väg
newOrder.Customer = oldOrder.Customer
...
eller via ett ramverk som du kanske bygger själv där du via XML eller nått förklarar hur objekten skall mappas... Lite som en ORM men mellan objekt.
OOM...
mappningslagret mappar mina old objekcts till mina nya objects som faktureringsmodulen nyttjar.
Aha, oki! :)
Men vad blir egentligen vinsten med det?
Alltså att mappa alla mina gamla och andra ev. konstiga orderobjekt till mitt "nyaste" och därifrån mappa om till 3-part.
Mot att mappa alla objekt direkt till 3-part.
mappningslagret mappar mina old objekcts till mina nya objects som faktureringsmodulen nyttjar.
Aha, oki! :)
Men vad blir egentligen vinsten med det?
Alltså att mappa alla mina gamla och andra ev. konstiga orderobjekt till mitt "nyaste" och därifrån mappa om till 3-part.
Mot att mappa alla objekt direkt till 3-part.
Vinsten är tid i så fall.
Dvs du behöver bara skriva kod en gång för mappa och kod en gång för hantera fatkurering...
Sen så behöver du i princip bara skvia mappingsfiler för alla andra gånger...
Detta var en idé, vet ej om det fungerar för dig... Men normalt brukar man föredra att ha ett lager som mappar, typ lite som att ha vyer i en kass db för få tydlig db...
Object Mapper kan göras med manuell mappning... Gör så den tar emot mapperklass det är snyggare.
Dvs.
OldOrderToNewOrderMapper : IObjectMapper
...
public IOrder MappObject(OldOrder oldOrder,NewOrder newOrder)
{
newOrder.Name = oldOrder.Title; <---- typ om de har olika namn
...
return neworder;
}
public class ObjectMapper
{
public ObjectMapper (IObjectMapper objectMapper)
{
public T MappObject<T>();
{
return objectMapper.MappObject();
}
...
}
public class invoiceService()
{
public void SaveInvoiceForOrder(IOrder order)
{
...
}
{
tja... nu är detta mega error code. men ville bara visa lite tanken... Hur du skulle kunna göra...
Har labbat lite nu och jag börjar få en bild av hur det bör funka! :D
En sak förstår jag dock inte: interfacet!
Jag har fått för mig, precis som ni nämner, att jag bör ha ett interface som hanterar de olika orderobjekten. Men hur ska jag definiera det? Ska det motsvara, som du skriver Johan, det "nyaste" orderobjektet? Det skulle då bli så här:
public class NewOrder
{
public int Id { get; set; }
public DateTime OrderDate { get; set; }
...
}
public class OldOrder
{
public string Id { get; set; }
public DateTime OrderDate { get; set; }
...
}
public interface IOrder
{
public int Id;
public DateTime OrderDate;
}
Och för att kunna använda det gamla orderobjektet så måste det först mappas till ett nytt orderobjekt. Är det korrekt?
Det känns dock fel! För i mitt huvud blir interfacet överflödigt, jag kan ju mappa det gamla orderobjektet ändå!
Hur kan/ska interfacet användas? Eller har jag missuppfattat dess användning?
Överflödigt? Nej då. ;)
Tänk om du ett år skapar ytterligare en version av Order, då måste du skapa en ny mappning för att matcha alla tre olika typer av ordrar. Om du istället skapar ett interface, som definierar de vitala metoderna för att kunna fakturera, och låter den framtida Order-klassen implementera den - så är ju allting löst. Då vet du hur du ska hantera objektet, eftersom att det inte spelar någon roll om det är en gammal Order-typ, ny Order-typ eller framtida Order-typ.
Själv tycker jag att namn som IOrder osv. är förkastligt på interfaces. Namnet ska representera vad interfacet gör, i verb-form. Runnable, Comparable, osv. - i ditt fall borde benämningen på interfacet vara typ Invoiceable. Rätt självklart vad objekt av typen Invoiceable är kapabla till - nämligen att kunna faktureras. :)
Överflödigt? Nej då. ;)
Tänk om du ett år skapar ytterligare en version av Order, då måste du skapa en ny mappning för att matcha alla tre olika typer av ordrar. Om du istället skapar ett interface, som definierar de vitala metoderna för att kunna fakturera, och låter den framtida Order-klassen implementera den - så är ju allting löst. Då vet du hur du ska hantera objektet, eftersom att det inte spelar någon roll om det är en gammal Order-typ, ny Order-typ eller framtida Order-typ.
Själv tycker jag att namn som IOrder osv. är förkastligt på interfaces. Namnet ska representera vad interfacet gör, i verb-form. Runnable, Comparable, osv. - i ditt fall borde benämningen på interfacet vara typ Invoiceable. Rätt självklart vad objekt av typen Invoiceable är kapabla till - nämligen att kunna faktureras. :)
Detta kräver ju dock att han har tillgång att kompilera om alla projekten samt att de gamla projekten måste ha referenser till det nya projektet med IInvoiceable.
I detta fallet kanske han har befogenheter att göra detta, men hur skall man göra i andra fall? Då blir en mappning eller en wrappning aktuellt.
Inte om han skapar en mapper nu för de gamla objekten, och i framtiden använder samma interface som han använder vid mappningen.
Var lite snabb, du hann också redigera. :)
Ja visst, mappningen blir han antagligen tvungen till - men som sagt, om han skapar ett interface Invoiceable nu så kan han använda det vid framtida nya Order-klasser.
som definierar de vitala metoderna för att kunna fakturera
Nu trilla visst någonting ner tror jag! :D
Rätta mig om jag har fel nu men interfacet är inte en implementering av det nya orderobjektet utan mer av de metoder och medlemmar som 3-parts objektet innehåller.
Om vi säger att 3-partsobjektet behöver ha ett orderid (string) samt orderdatum (Datetime) för att kunna skapa en faktura så ska interfacet innehålla dessa medlemmar. Rätt?
Alltså:
public interface Invoiceable
{
public string OrderId;
public DateTime OrderDate;
...
}
Men betyder inte det att mina orderobjekt måste implementera dessa då så att ex. det nya orderobjektet kommer att se ut:
public class NewOrder : Invoiceable
{
public int Id { get; set; }
public DateTime OrderDate { get; set; }
...
public string OrderId {
get {
return Id.ToString();
}
set;
}
}
Men betyder inte det att mina orderobjekt måste implementera dessa då så att ex. det nya orderobjektet kommer att se ut:
Nej och Jo! :)
Alla orderer-objekt som du vill kunna fakturera på måste implementera detta Interface, eftersom det är Interfacet som din faktureringstjänst tar emot i sin metod, inte något objekt.
Men om du inte vill in och ändra i din gamla kod, alltså implementera IOrder till dina gammla objekt, så måste du ju mappa om från dina gamla order till dina nya order som har implementerat IOrder interfacet. Vilket säkert är den lösning som är bäst att implementera...
Tänk dock igenom minst 15 gånger på att ditt IOrder verkligen är rätt utformat även för framtida krav, då interfacen helst inte skall ändras stup i kvarten. Dessutom så skall dessa interface delas mellan flera olika projekt vilket gör att du bör lägga dessa i en helt egen assembly utanför både ditt nya och gamla projekt, så du inte behöver ha några referenser till något av dessa projekt, om du behöver implementera IOrder till något annat projekt.
Aha, ja, men då var jag inte helt fel ute! :)
Och då jag vet exakt hur 3-part vill ha ordern så borde jag kunna designa interfacet efter den strukturen. Då kommer jag ju aldrig behöva skriva om interfacet så länge 3-part inte skriver om faktureringstjänsten. Rätt?
Är det inte fiffigast sedan att skapa ett helt nytt orderobjekt?! ;)
Alltså, ett orderobjekt som är designat bara för faktureringstjänsten och sedan mappa alla mina orderobjekt till detta objekt?
Men om jag gör så så känns det som om jag är tillbaka på ruta ett. För då kan jag ju mappa alla typer av orderobjekt till "faktureringsorderobjektet" och sedna bara använda det utan ett interface!
Fan att detta ska vara så svårt att få in i skallen då! :OO
Blir det så här kanske:
Jag har två val:
1. Implementera interfacet på min orderklass.
Då måste jag lägga till medlemmar, metoder osv. som interfacet kräver. Jag behöver dock ingen övrig mappning.
2. Inte implementera interfacet på min orderklass.
Då måste jag istället mappa mitt objekt till en annan orderklass som har interfacet implementerat.
Jag har nu skapat ett orderinterface och implementerat krävda medlemmar i orderklassen. Så långt allt väl!
Nu behöver jag bygga på med en samling (IList) av fakturarader i interfacet men det ställer till trubbel.
Orderklassen ser ut så här:
public class Order : IInvoiceableOrder
{
public int Id { get; set; }
...
private IList<OrderItem> _orderItems;
public IList<OrderItem> Items
{
get {
if (_orderItems == null)
_orderItems = new List<OrderItem>();
return _orderItems; }
set { _orderItems = value; }
}
}
public class OrderItem : IInvoiceableOrderItem
{
public int Id { get; set; }
public string ArticleNr { get; set; }
...
}
Felet är: 'Order' does not implement interface member 'IInvoiceableOrder.Items'. 'Order.Items' cannot implement 'IInvoiceableOrder.Items' because it does not have the matching return type of 'System.Collections.Generic.IList<IInvoiceableOrderItem>'.
Hur löser jag det?
Jag vill ju kunna använda orderklassen som den är med "vanliga" OrderItems i andra sammanhang än fakturering och då få tillgång till klassens samtliga medlemmar. Men däremot om jag går över till att använda IInvoiceableOrder så vill jag ha en IList med IInvoiceableOrderItem.
Jag vill ju inte gärna göra en extra samling i orderklassen, Items2 som då skulle vara en lista av IInvoiceOrderItem.
Vid deklarationen av metoden Order.Items har du ju retur-typen av IList<OrderItem> - den ska vara IList<IInvoiceableOrderItem>.
Men jag tycker fortfarande inte om din namnsättning... Den borde vara Invoiceable för Orders som ska gå att fakturera, samt kanske Orderable för OrderItem's som ska gå att lägga i en order. Orderable känns dock som ett överflödigt interface - men jag har ju ingen insyn i hur projektet/-n fungerar. ;)
Red.}
Jag vill ju kunna använda orderklassen som den är med "vanliga" OrderItems i andra sammanhang än fakturering och då få tillgång till klassens samtliga medlemmar. Men däremot om jag går över till att använda IInvoiceableOrder så vill jag ha en IList med IInvoiceableOrderItem.
Kan en Order hantera OrderItems som inte ska finnas med på fakturan?
Det är ju det som är det luriga... Kom också ihåg att du kan låta en klass implementera fler än ett interface.
Vid deklarationen av metoden Order.Items har du ju retur-typen av IList<OrderItem> - den ska vara IList<IInvoiceableOrderItem>.
Det går/vill jag inte.
Det är endast om en order ska betalas med faktura som den går över och blir en IInvoiceOrder. Betalar man ex. med kontokort så är ordern just en Order.
Och har man betalat med kort så vill jag ju inte hämta en Order tillsammans med en lista av IInvoiceOrderItem utan OrderItem.
SPiN skrev:
Kan en Order hantera OrderItems som inte ska finnas med på fakturan?
Japp, se svar ovan.
Jag labbade lite och fick till det så här:
public Order : IInvoiceableOrder
{
...
public IList<OrderItem> Items
{
get {
if (_orderItems == null)
_orderItems = new List<OrderItem>();
return _orderItems; }
set { _orderItems = value; }
}
public IList<IInvoiceableOrderItem> OrderItems
{
get
{
return Items as IList<IInvoiceableOrderItem>;
}
set { }
}
}
Men knappast optimalt då jag helt plötsligt har två samlingar av nästan samma sort.
Men det kanske är som du skriver, OrderItem kanske inte behöver ett eget interface.
Det är bara det att mina propertys i orderitem inte stämmer 100% med 3-parts fakturarader. Men jag kanske kan skippa interfacet och bara mappa om de propparna som behövs istället.
SPiN skrev:
Men jag tycker fortfarande inte om din namnsättning
Hehe! Jag tyckte att det blev förvirrande utan den typ av namn, det blev då typ:
IInvoiceable order = new Order();
Då blev IInvoiceable så luddigt.
Typen av namnsättningen är ju också rätt vanlig, ex. IList, IOrderedEnumerable...
Men du kanske inte gillar dem heller?! :)
Nä, jag tycker [oftast] inte om Microsofts sätt att namnge interfaces. ;) Eftersom att dom har rippat en hel del från Java, tycker jag definitivt att de kunde rippat Java Naming Conventions också. ;)
Jag tror att du missförstår interfaces lite. Ett interface ska visa vad som går att göra med ett objekt som implementerar interfacet. T.ex. Invoiceable <- lätt att förstå att klasser som implementerar detta interface går att hantera i fakturor. Inte att de måste hanteras i fakturor. En order som är Invoiceable kan ju fortfarande vara "CreditCardPayable". :)
Men jag förstår att det är svårt att komma runt då du redan har skapat två olika typer av Orders (och antagligen OrderItem's?). Man kan ju inte säga riktigt hur du ska applicera det här på ditt projekt, då man inte vet hur de olika klasserna ser ut samt var för information som skiljer dem åt.
263 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2