Om man ska bygga klasser om t.ex. bilar åt en bilhandlare, hur skulle ni göra då:
skapa en klass som heter: "Car" (som innehåller div. egenskaper och metoder om en bil)
skulle ni också skapa en som heter "Cars" (som innehåller div. egenskaper och metoder om flera bilar)?
jag kommer inte riktigt på vad den undre skulle kunna innehålla för något men är det vettigt att ha två klasser?
(man kanske inte behöver "Cars" utan man kanske går direkt på en klass som heter "Garage" som innehåller flera "Car" objekt!)
Om man ska bygga klasser om t.ex. bilar åt en bilhandlare, hur skulle ni göra då:
skapa en klass som heter: "Car" (som innehåller div. egenskaper och metoder om en bil)
skulle ni också skapa en som heter "Cars" (som innehåller div. egenskaper och metoder om flera bilar)?
jag kommer inte riktigt på vad den undre skulle kunna innehålla för något men är det vettigt att ha två klasser?
(man kanske inte behöver "Cars" utan man kanske går direkt på en klass som heter "Garage" som innehåller flera "Car" objekt!)
Det låter som om du menar att Garage är en collection som håller Car-objekt. Isf. borde Garage heta CarCollection. :)
Jag skulle skapa en som heter Car och sedan använda GenericCollections för att hantera flera, t ex
List<Car> CarCollection = new List<Car>();
CarCollection.Add(myCar);
Jag skulle skapa en som heter Car och sedan använda GenericCollections för att hantera flera, t ex
List<Car> CarCollection = new List<Car>();
CarCollection.Add(myCar);
Absolut är det en jättebra lösning, men ibland kan det krävas mer funktionalitet i samling av bilar, t.ex. om man vill byta däck på alla bilar så kanske en metod på samlingen hade passat bra.
listOfCars.ChangeTires();
som inne i CarCollection utför denna kodsnutt t.ex.
public void ChangeTires()
{
foreach(Car car in this)
car.ChangeTires();
}
Detta kanske var ett dåligt exempel, men ibland kanske man vill att listorna skall kunna utföra speciella saker, men man kan fortfarande använda generics och låta CarCollection ärva av List<Car>.
Jag brukar bygga upp de flesta system enligt följande regler:
CarEntry - bilen ifråga (en hög med egenskaper helt enkelt)
Cars - hantera bilar (lägga till, ta bort, uppdatera etc)
CarCollection - bilar i listform (generics etc)
Alltid starkt typade objekt (heter det så på svenska förresten? typsäkra objekt kanske?).
Måste bara fråga det ultimata hade varit så som du beskriver
en objektklass Car och en Repository för Cars som du kallar Cars och en CarCollection, men när det gäller din Cars/Repository klass så fungerar väl inte ASP.NET's kontroller till 100% för det tankesättet utan vill ha Save, Update, Delete på själva entitet's objektet, eller har jag fattat detta fel?
Måste bara fråga det ultimata hade varit så som du beskriver
en objektklass Car och en Repository för Cars som du kallar Cars och en CarCollection, men när det gäller din Cars/Repository klass så fungerar väl inte ASP.NET's kontroller till 100% för det tankesättet utan vill ha Save, Update, Delete på själva entitet's objektet, eller har jag fattat detta fel?
Varför skulle jag ha Save eller Update på själva bilen?
Så här menar jag i lite pseudokod (försöker mig på C#, rätta mig gärna om jag gör några syntaxfel):
[b]class Cars[/b]
{
public CarEntry Save(CarEntry car)
{
// Spara bilen.
...
car.CarID = Autoincrement från databas eller motsvarande
return car
}
public void Update(CarEntry car)
{
// Dito.
}
}
[b]class CarEntry[/b]
{
public property string Engine
{
get { return _Engine }
set { _Engine = value}
public property string Color
{
get { return _Color }
set { _Color = value}
}
}
[b]class CarCollection : List<CarEntry>[/b]
{
}
All kommunikation (från presentationslagret till affärslagret) görs sedan med hjälp av klassen Cars. Om jag behöver en enskild bil så returneras en CarEntry. Om jag behöver en lista över bilar returneras en CarCollection<CarEntry>.
men när det gäller din Cars/Repository klass så fungerar väl inte ASP.NET's kontroller till 100% för det tankesättet utan vill ha Save, Update, Delete på själva entitet's objektet, eller har jag fattat detta fel?
ASP.NET:s kontroller har överhuvud taget ingen vidare koll på hur det ska hantera entiterna, så att sätta Update, Delete etc. direkt på domänklasserna (ActiveRecord-pattern) ger ingen konkret fördel (sedan kan man gilla den lösningen ändå, men det är en annan diskussion).
Pace skrev:
Om jag behöver en lista över bilar returneras en CarCollection<CarEntry>.
Snarare en CarCollection : List<CarEntry> el. likn väl?
En fundering Pace:
Lägger du endast egenskaper och inga metoder alls i din CarEntryklass?
Det är så jag gör iaf, jag har en klass som heter Car och en som heter CarDB, Car innehåller enbart egenskaperna för bilen och CarDB innehåller alla funktioner so t ex Get, GetAll, Save, Update, GetSearch osv beroende på de funktioner man vill ha. Jag har funnit att i ett sånt här scenario fungerar det bra med statiska metoder:
Car myCar = CarDB.Get(1);
List<Car> myCarColl = CarDB.GetBySearch("Toyota");
bool result = CarDB.Update(myCar);
osv.
Pace's lösning ger ju också fördelen att det blir enkelt att binda datat till t.ex. en objectdatasource, bara att välja metoderna från Cars-klassen som Update/Select etc.
En fundering Pace:
Lägger du endast egenskaper och inga metoder alls i din CarEntryklass?
Precis.
P skrev:
Pace's lösning ger ju också fördelen att det blir enkelt att binda datat till t.ex. en objectdatasource, bara att välja metoderna från Cars-klassen som Update/Select etc.
Framför allt jobbar man med en helt abstrakt lösning. Koden för att lägga till en ny användare kan se ut så här:
// Skapa användare.
User user = new UserEntry;
user.Name = "Pace";
user.Email = "anonymous@localhost";
user.Active = True;
// Spara användare.
Users users = new Users;
users.AddUser(user);
Och hämta en användare:
Users users = new Users;
User user = Users.GetUserById(464);
Response.Write(String.Format("Jag heter {0}.", user.Name));
Det är inte så mycket att missförstå med en sådan enkel kod.
Någon active record-mönster kör jag inte med, utan i mitt publiceringssystem sker det ganska många transaktioner vid en updatering eller borttagning. Men det behöver ju aldrig användaren veta, eftersom abstraktionen förenklar allt (och i datalagret förenklas ytterligare genom stored procedures etc).
Pace -> Hur fungerar det med abstarkta klasser egentligen? Vad vinner man på det?
Jag kör som jag sa tidigare mest med statiska funktioner, vilket har fungerat bra för mig och det är enkelt att hämta m.m.
Car myCar = CarDB.Get(123);
Det blir ju betydligt enklare på alla plan. Enkhelhet innebär också mindre risk för att göra fel, det enda jag gör är att binda värden till objekt. Dessutom blir underhållet mindre. Fast det är ju vanlig tre-lager-lösning i botten, affärslogiken tar ju hand om det "tråkiga".
Inom objektorienterad systemutveckling byggs hela systemet kring en informationsmodell. Modellen består av klasser och relationer som utgör abstraktioner av föremål och företeelser i den verksamhet som systemet ska stödja.
Inom datavetenskap innebär abstraktion att man döljer de tekniska detaljerna bakom ett lager av kod som erbjuder ett enklare gränssnitt mot omvärlden.
Lägger du endast egenskaper och inga metoder alls i din CarEntryklass?
Den frågan pekar åt två, tre håll i den här diskussionen.
1. Lägger du lagringsmetoderna i entitetsklassen? (ActiveRecord)
Detta är ett populärt pattern , och med all rätta. I enklare system utan invecklad affärslogik kan det definitivt vara ett bra sätt. Man kan med fördel använda CastleProjects ActiveRecord-implementering för detta.
Exempel:
Car car=Car,Find(myCarId);
car.Model="244DL";
car.Save();
2. Lägger du några metoder alls i klasserna?
Det är inte alltid så lyckat att man att klasserna som verkar i domänen är samma som lagras ("persistas") i databasen. Man kanske vill skicka objekten via en webservice el. liknande, och då är inte ett fullt utsmyckat objekt så hanterbart. Man skapar då en DTO -klass (Data Transfer Object) som bara innehåller värden, och som sedan används som ett mellansteg mellan lagring och färdig instans.
CarDto c=SomeDbClass.FindCar(myCarId);
Car car=CarAssembler.InstanceFromDto(c);
car.Model="244DL";
c=CarAssembler.DtoFromInstance(car);
SomeDbClass.SaveCar(c);
Pace skrev:
Framför allt jobbar man med en helt abstrakt lösning. Koden för att lägga till en ny användare kan se ut så här
Nog för att jag en stark tillskyndare av abstraktion, men jag förstod inte riktigt relevansen i det exempel du gav (User/UserEntry). Kan du förklara?
Har kommit fram till denna modell vilket medför att jag undviker "tunga" entitetsklasser. Vet inte hur "rätt" den är, men den är lätt att arbeta med och i mitt tycke väldigt logisk.
public partial class SomePage: PageBase
{
private void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Bind();
}
}
private void Bind()
{
Customer c = Customer.GetCustomer(Profile.CustomerId);
lFirstname.Text = c.FirstName;
//...
}
}
public class Customer
{
#region Constructors
public Customer()
{
}
#endregion
#region Property fields
private int _id;
private string _firstname;
private string _lastname;
#endregion
#region Properties
public int Id
{
get { return _id;}
set { _id = value; }
}
public string FirstName
{
get { return _firstname;}
set { _firstname= value; }
}
public string LastName
{
get { return _lastname;}
set { _lastname= value; }
}
#endregion
#region Instance methods
public Customer Create()
{
return Adapter.Customer.Create(this);
}
#endregion
#region Static methods
public static Customer GetCustomer(int customerid)
{
return Adapter.Customer.GetCustomer(customerid);
}
#endregion
}
public static class Adapter
{
public static SqlCustomerProvider Customer
{
get
{
return new SqlCustomerProvider();
}
}
}
public class SqlCustomerProvider
{
public SqlCustomerProvider()
{
}
public Customer Create(Customer customer)
{
SqlDatabase db = new SqlDatabase(Utility.DataBase.GetConnectionString());
...
//Databashantering
...
return customer;
}
public Customer GetCustomer(int customerid)
{
SqlDatabase db = new SqlDatabase(Utility.DataBase.GetConnectionString());
...
//Databashantering
...
return col;
}
}