webForumDet fria alternativet

Klasser i plural och/eller singular

.NETur .NET

43 svar · 1 621 visningar · startad av doggelito

Medlem sedan juni 20003 076 inlägg
Frågan#1

En liten fundering bara:

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!)

Medlem sedan feb. 20002 300 inlägg
#2

doggelito skrev:

En liten fundering bara:

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. :)

Medlem sedan jan. 20013 341 inlägg
#3

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);

Medlem sedan juni 20003 076 inlägg
#4

Phorpher skrev:

Det låter som om du menar att Garage är en collection som håller Car-objekt. Isf. borde Garage heta CarCollection.

Jepp, så menade jag! :)

aleborg skrev:

Jag skulle skapa en som heter Car och sedan använda GenericCollections för att hantera flera

GenericCollections, det får jag ta å kolla in lite närmare!

Tack så länge! :bire

Medlem sedan aug. 20003 575 inlägg
#5

aleborg skrev:

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>.

Medlem sedan juni 20019 024 inlägg
#6

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?).

Medlem sedan aug. 20003 575 inlägg
#7

Pace skrev:

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?

Medlem sedan juni 20019 024 inlägg
#8

Nickemannen skrev:

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>.

Medlem sedan dec. 19996 721 inlägg
#9

Nickemannen skrev:

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?

Medlem sedan juni 20019 024 inlägg
#10

emission skrev:

Snarare en CarCollection : List<CarEntry> el. likn väl?

Så kanske det ska vara, ja. Tack. :)

Trevligt att se dig här på "kvällskvisten" också. :e

Medlem sedan juni 20003 076 inlägg
#11

Va intressant det blev! :)

En fundering Pace:
Lägger du endast egenskaper och inga metoder alls i din CarEntryklass?

Medlem sedan jan. 20013 341 inlägg
#12

doggelito skrev:

Va intressant det blev! :)

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.

Medlem sedan juni 20003 076 inlägg
#13

Oki! :bire
Jag har inte hela bilden klar i huvudet men den blir tydligare å tydligare. :)

Medlem sedan jan. 20012 204 inlägg
#14

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.

Medlem sedan juni 20019 024 inlägg
#15

doggelito skrev:

Va intressant det blev! :)

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));

Binda till en listkontroll:

Users users = new Users;
ddl.DataSource = Users.GetActiveUsers();
ddl.DataValueField = "UserID";
ddl.DataTextField = "Name";
ddl.DataBind();

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).

Medlem sedan jan. 20013 341 inlägg
#16

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);

Medlem sedan juni 20019 024 inlägg
#17

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".

Som Wikipedia säger:

http://sv.wikipedia.org/wiki/Abstraktion skrev:

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.

Medlem sedan dec. 19996 721 inlägg
#18

doggelito skrev:

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?

Medlem sedan sep. 20011 914 inlägg
#19

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;
        }
}
Medlem sedan jan. 20012 204 inlägg
#20

I Pace's lösning så sparar du din data i en klass CarEntry och du har all din affärslogik i en annan.

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