webForumDet fria alternativet

Arkitektur på objekt

32 svar · 1 261 visningar · startad av Lilly

LillyMedlem sedan okt. 200637 inlägg
#1

I min förra tråd pratade vi lite om konstruktorn. Nu skulle jag vilja prata lite om arktiketuren för olika objekt. Om vi börjar med anropen till tex ett customer objekt. Hur ser ni på denna struktur? Skulle ni gjort likadant?

// Instantiate the Customer class using the default constructor Customer
customer = new Customer();
// Assign some of its properties
customer.LastName = "Jones";
customer.FirstName = "Jeff";

// Call its Create() method to save the values in the database, and get its new primary key (CustomerID) value
int customerID = customer.Create();

// Instantiate the Customer class using the constructor that takes the CustomerID as a parameter
Customer customer2 = new Customer(customerID);
Trace.Write("LastName: " + customer2.LastName);
Trace.Write("FirstName: " + customer2.FirstName);

// Change the value of the first name then save the changes to the database
customer2.FirstName = "Stephanie";
customer2.Update();

// On second thought, let's just delete the record entirely
customer2.Delete();

Källa: http://www.awprofessional.com/articles/article.asp?p=382852&seqNum=1&rl=1

Peter SMedlem sedan dec. 20025 483 inlägg
#2

Jag tycker det verkar omständligt. Istället skulle jag kanske göra så här:

Customer customer1 = new Customer("Jeff", "Jones");

Customer customer2 = new Customer(); // no name specified
customer2.setFirstName("Stephanie");
customer2.setLastName("Foobar");

// provide a method for access to the customer's id
customer.getId();

// delete customers
customer2.delete();
customer1.delete();
LillyMedlem sedan okt. 200637 inlägg
#3

Jag har några frågor. Du har tex setFirstName och setLastName. Jag antar att du även har funktioner som heter tex getFirstName och getLastName. Varför inte baka ihop dessa så att det heter bara FirstName och LastName som ovan?

Customer.getId() förstår jag inte riktigt. Skapar du en ny kund i databasen via det och sätter id:et sedan i en property i objektet?

Hur gör du förresten med update:n av customer i databasen?

I din delete tar du även bort en kund i databasen?

Många frågor :)

Peter SMedlem sedan dec. 20025 483 inlägg
#4

Syftet med exemplet att använda get-/set-metoder var att man i dem sköter uppdatering av kundinformation (pseudokod):

Customer c = Customer.get("<SSN of customer>");

if c: // change customer's first name
  c.setFirstName("...");

Beroende på valet av språk kanske detta även går att åstadkomma vid tilldelning av egenskaper.

Customer.getId() lade jag endast till som exempel. Meningen är inte att kunden skapas genom ett anrop till den. Det sker i konstruktorn (det kan därför vara skumt att kunna skapa kunder med en tom konstruktor som i exemplet).

Kunden kan tas bort genom ett anrop till delete()-metoden.

JonMedlem sedan juli 20011 304 inlägg
#5

Jag skulle ha gjort precis som du gör i det första exemplet. Det enda jag skulle ändra på är customer.Create(); Det är ett lite dumt namn eftersom man associerar det med skapande av objekt. Jag skulle döpa den till customer.Persist(); eller customer.Save();

Jag ser ingen anledning att använda get och set-metoder i .Net när det finns get/set-properties :)

Ska man gå ännu längre skulle jag ha en Manager som uppdaterar/hämtar/sparar mina klasser till någon typ av datakälla. Men där går åsikterna ibland isär var man ska lägga ansvaret.

Personligen tycker jag inte att när man frågar sig vad en person bör kunna, veta och ha ansvar för så ryms inte datakällan där. Men det är som sagt ett litet sidospår...

LillyMedlem sedan okt. 200637 inlägg
#6

Peter S
Vad är det som händer när du gör tex setFirstName? Sker det då en databasuppdatering direkt eller har du någon update som exekurerar uppdateringen i databasen?

Jon
Själv gillar jag nog "create" mer men jag förstår vad du menar. En annan sak som jag undrar över är att anta att vi har typ 10-15 properties på kundobjektet. Allt från kundnamn, personnummer till adress och mailadress m.m. När du skapar ditt kundobjekt skulle du då göra enligt följande:

customer = new Customer();
customer.X = X
customer.X1 = X1
customer.X2 = X2
...
customer.X15 = X15
int customerID = customer.Create();

Eller skulle man hellre göra det på ett annat sätt?

Om du hittar någon artikel eller något om den där manager klassen som du nämnde så får du gärna tipsa!

CompusaMedlem sedan jan. 20023 327 inlägg
#7

Peter S skrev:

Jag tycker det verkar omständligt. Istället skulle jag kanske göra så här:

Customer customer1 = new Customer("Jeff", "Jones");

Customer customer2 = new Customer(); // no name specified
customer2.setFirstName("Stephanie");
customer2.setLastName("Foobar");

// provide a method for access to the customer's id
customer.getId();

// delete customers
customer2.delete();
customer1.delete();

Detta är exemplariskt om det handlar om Java. I .NET finns som sagt properties, men är det okej att skippa accessor- och mutator-metoder ur ett "snyggt" objekt-orienterat perspektiv?

Lilly skrev:

Peter S
Vad är det som händer när du gör tex setFirstName? Sker det då en databasuppdatering direkt eller har du någon update som exekurerar uppdateringen i databasen?

Jag visar det i Java-kod men det är nästan samma ;)

public class Person {

    private String fname;

    /** Empty constructor */
    public Person() {
    }

    public String getFname() {
        return fname;
    }

    /* this refererar till instansvariabeln */
    public void setFname(String fname) {
        this.fname = fname;
    }

    /* alternativ implementering av setFname */
    //public void setFname(String name) {
    //    fname = name;
    //}

}

/* För att använda klassen */
Person person = new Person();
person.setName("Joel");
person.getName(); /* Returns Joel */
person.setName("Åke");
person.getName(); /* Returns Åke */
Peter SMedlem sedan dec. 20025 483 inlägg
#8

Jag var som sagt lite lur på att properties i .NET fungerar på ett speciellt sätt. Det verkar därför vettigt att utnyttja den teknik som erbjuds.

Vad gäller get-/set-metoder fyller de sina funktioner då datainkapsling eftersträvas. Egenskaper som för- och efternamn göres i sådana fall privata.

Lilly »
Ursprungstanken var det. Dock blir det väl litet väl många databasfrågor om flera egenskaper skall uppdateras med detsamma, istället för att göra en UPDATE i vilken allt magiskt händer ;)

LillyMedlem sedan okt. 200637 inlägg
#9

Compusa
Men hur skulle Java hanterat databasuppdateringen på ett optimalt sätt enligt den strukturen ovan? För det är ju inte optimalt att uppdatera databasen per property som sätts.

CompusaMedlem sedan jan. 20023 327 inlägg
#10

Finns många olika sätt ;)
Ett är design-mönstret DAO, Data Access Object. Där kan man använda sig av något som kallas transfer objekt. Mycket intressant läsning finns här:
http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

Jag har själv implementerat det i en blogg-applikation som jag håller på att utveckla och det är mycket användbart. Eftersom man kan implementera för olika data-källor men mot ett gemensamt interface så krävs det i stort sett inga ändringar i koden om du skulle vilja byta ut din datakälla från exempelvis en en mySQL databas till en textfil, alternativt en annan databashanterare.

JonMedlem sedan juli 20011 304 inlägg
#11

För att reda ut eventuell förvirring: Properties i .NET blir till get/set-metoder när de kompileras, men ser det bara inte. Så det är egentligen samma sak rent objektorienteringsmässigt. :)

Lily
Det är svårt att ge ett bra övergripande exempel. Folk gör ganska olika och det går att göra det hela med en massa olika grader av komplexitet. Jag tycker personligen väldigt mycket om DTO:er som Compusa talar om. En del lägger som sagt uppdateringslogiken mot databasen i själva objekten och en del i manager-klasser.

När jag har resurser till det så går jag gärna hela vägen och låter en Factory ge mig nya objekt, en objecthandler uppdatera dem och gärna en Unit of work som har alla förändrade objekt i sig och uppdaterar dem mot en datakälla. Gå som sagt att göra hur komlicerat som helst.

Det viktiga anser jag vara att få koll på grundläggande oo-principer och de vanligaste förekommande patterns som används. Ett pattern är ett vanligt återkommande sätt att lösa ett objektorientarat scenario på kan man säga. Lite exempel på patterns

Vet inte om du blev klokare av detta men du är ju på rätt väg: ställer frågor om hur man hanterar objektorienteringen. Fråga på!

CompusaMedlem sedan jan. 20023 327 inlägg
#12

Jon skrev:

Vet inte om du blev klokare av detta men du är ju på rätt väg: ställer frågor om hur man hanterar objektorienteringen. Fråga på!

Jag tror att man aldrig kan bli full-lärd när det gäller objektorienterad programmering, men man kan alltid bli bättre. Precis som Jon säger, när man lärt sig grunderna om objektorienterad programmering så är det alltid nyttigt att lära sig etablerade design-mönster. En bok som jag kan rekommendera som första bok för detta är Head First Design Patterns. Boken är ganska roligt skriven, vilket gör läsningen betydligt behagligare:
http://www.adlibris.com/se/product.aspx?isbn=0596007124&s=1

För tre år sedan kunde jag inte ett skvatt om objektorienterad-programmering, men nu tänker jag aldrig byta tillbaka såvida det inte gäller ett system/mjukvara där ett programmeringsspråk utan objektorienterat stöd måste användas.

GladhMedlem sedan maj 20012 812 inlägg
#13

Jag är lite skeptiskt till att ha funktioner som Create(), Delete(), Update() på objektet själv. Det är bättre så fall att använda sig av Managerklasser för att hanterar detta, speciellt om det handlar om att persisterar ner objektet till ett lagringsmedium.

Alltså:

ManagerClass().Delete(object);
ManagerClass().Update(object);
ManagerClass().Load(id);

På detta sätt är det enkelt att byta ut vart du vill spara ner objektet eller från vart du vill skapa det. Du kan ha 2 olika ManagerClasser som gör olika saker med objektet när det skall skapas, fylla det med olika input data osv osv.

Eller så har du en stor managerclass som sköter nästan allt.

ManagerClass().Save(objcet, connectionString, Database.SqlServer);

Här kan du specificera till vilken databas så objektet skall sparas, eller om det kanske skall vara en XML-fil eller något annat.

Själv har jag byggt en enkelt OR-Mapper som fungerar så här:

TSList<Customer> customerList = new EntityBroker(connectionstring).Load<Customer>(query);

Customer customer = new EntityBroker(connectionString).Load<Customer>(identifier);

Där Customer objektet innehåller metadata om vilken tabell som den skall hämtas ifrån samt vilka kolumner i databasen som skall mappas till vilka variabler i objektet, eller så lägger jag den metadata i en XML-fil så jag kan ändra det om jag behöver flytta mellan olika databaser och inte kan ha samma namn på tabellerna...

Jag får alltså ut en lista med mina customer entiter utifrån en query som jag skickar in, eller ett specifik entitet från ett ID som jag skickar in. Att den använder sig av Generics gör det typsäkert fast jag bara har 3 metoder: Load(), Save(), Delete(), som i och för sig är överlagrade :)

- M

CompusaMedlem sedan jan. 20023 327 inlägg
#14

Gladh skrev:

Jag är lite skeptiskt till att ha funktioner som Create(), Delete(), Update() på objektet själv. Det är bättre så fall att använda sig av Managerklasser för att hanterar detta, speciellt om det handlar om att persisterar ner objektet till ett lagringsmedium.

Tänka sig att du tog upp någonting som jag precis funderat kring. Har sett många exempel där man använder sig av Create, Delete, Update i JavaBeans. Detta kan bli ganska smidigt om Java-bönan exempelvis anropar en DAOFactory för att hämta en DAO i respektive metod.

Då skulle en update metod i en Java-böna kunna se ut så här:

public boolean update() {
    DAOFactory dao = DAOFactory.getDAOFactory();
    CustomerDAO custDAO = dao.getCustomerDAO();
    custDAO.updateCustomer(this);
}

Är det detta du är skeptiskt till? I min nuvarande lösning sköter jag sådant här via Command-objekt som mappas av min FrontController. Detta blir ganska bökigt så jag funderar på att gå över till lösningen ovan, men har också alltid varit lite kritisk till att ha dessa metoder i objektet själv. Det här med ManagerKlasser har jag "sett" något om för en liten stund sedan tror jag. Frågan är exempelvis om inte min CustomerDAO är en form av manager klass???

NickemannenMedlem sedan aug. 20003 575 inlägg
#15

Hmm, jag hade nog kört en singleton på den såkallade Manager-klassen sedan låtit den anropat en factory isåfall för att skapa objektet. Sedan att managerklassen har alla objekt den sparat i en lista av något slag så att den inte behöver skapa om objektet om ett objekt med samma Id efterfrågas igen.

LillyMedlem sedan okt. 200637 inlägg
#16

Tack för alla åsikter! Detta med en manager tycker jag låter väldigt intressant. Jag skrev på ett annat forum och fick ett bra exempel på hur den "yttre" strukturen kunde se ut.

http://www.pellesoft.se/communicate/forum/view.aspx?msgid=231495&forumid=128&sum=0

För manager är väl samma sak som CustomerRepository i ovanstående länk? Vet ni om det finns någonstans någon bra exempelkod på detta?

CompusaMedlem sedan jan. 20023 327 inlägg
#17

Lilly skrev:

Tack för alla åsikter! Detta med en manager tycker jag låter väldigt intressant. Jag skrev på ett annat forum och fick ett bra exempel på hur den "yttre" strukturen kunde se ut.

http://www.pellesoft.se/communicate/forum/view.aspx?msgid=231495&forumid=128&sum=0

För manager är väl samma sak som CustomerRepository i ovanstående länk? Vet ni om det finns någonstans någon bra exempelkod på detta?

Om detta är vad Gladh menar så ser jag ingen större skillnad mellan detta och design-mönstret DAO. Olika namn på samma sak?

LillyMedlem sedan okt. 200637 inlägg
#18

Compusa
Jag misstänkte att det var det du pratade om och jag tror att det är snarlikt om inte exakt samma sak som Gladh pratar. Eller hur är det, Gladh?

PS. Jag har inte läst artikeln du hänvisade till men jag har i alla fall skrivit ut den ska försöka läsa den imorgon...

LillyMedlem sedan okt. 200637 inlägg
#19

Jag hittade en sida nu på morgon som ger lite exempelkod på något snarlikt kanske. Jag har ännu inte hunnit läsa artikeln men det såg spontant rätt okej ut :)

http://steve.emxsoftware.com/Domain+Driven+Design/DDD+Repositories++Factories

GladhMedlem sedan maj 20012 812 inlägg
#20

compusa skrev:

Är det detta du är skeptiskt till?

Både ja och nej. Det är bra att det inte är ditt objekt i sig själv som sköter updateringen utan du har lagt ut det i någon annanstans, att du sedan wrappar det i ditt objekt är väl okej, även om jag inte tycker det behövs eller är snyggt.

Det är inte bra att du har specifika funktioner för att skapa och spara varje objekt.

dao.getCustomerDAO();

border vara:

dao.GetAnyObjectDAO();

På detta sätt får du mindre (men mer komplex) kod. Nu är det egentligen inget problem då de flesta av dessa DAOFactorys oftas genererars från något program, men om man vill gå in och ändra något generellt för alla klasser så måste man gå in i alla GetObjectDAO() metoder och ändra i dessa istället för att bara ändra i GetAnyObjectDAO().

lilly skrev:

För manager är väl samma sak som CustomerRepository i ovanstående länk?

Japp och och Patrik pratar om samma sak, med olika namn bara, och det är näste samma sak som Compusa pratar om, Compusa har dock spcifika Factory-klasser för varje typ av objekt som skall skapas, jag och Partik pratar om en generell factoryklass.

lilly skrev:

Vet ni om det finns någonstans någon bra exempelkod på detta?

Exempelkod för Managerklassen eller hur du använder den för att hanterar dina objekt?

nickemannen skrev:

Hmm, jag hade nog kört en singleton på den såkallade Manager-klassen sedan låtit den anropat en factory isåfall för att skapa objektet.

Manager klassen är Factoryklassen, bara ett annant namn på den. Det är dock ingen specifik factoryklass för en specifik type av objekt, utan en generell factoryklass som kan skapa alla olika typer av objekt som jag vill....

nickemannen skrev:

Sedan att managerklassen har alla objekt den sparat i en lista av något slag så att den inte behöver skapa om objektet om ett objekt med samma Id efterfrågas igen.

Ahhh... caching, visst skall man bygga in caching i sin managerklasser.
Men man skall använda det med suntförnuft, eftersom det kan vara så att andra program kan gå ner och ändra i databasen för ett objekt som du har i din cache, och när du då inte hämtar upp det igen från databasen utan hämtar det från din cache, så har du inte ett korrekt data objekt, eftersom datan i databasen inte stämmer överens med den data som du har i din cache... Samt att du måste hantera möjligheten att ta bort dess objekt när minnet börjar ta slut, för du vill ju inte att din applikation skall dö bara för att du fyllt din cache med en massa objekt som du inte använder :)

Så cache är bra när man vet hur och när man skall använda det...

- M

146 ms totalt · 3 externa anrop · v20260731065814-full.fb544a5a
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
142 ms — hämta tråd, inlägg och bilagor (db)