开发者

Good class design by example

I am trying to work out the best way to design a class that has its properties persisted in a database. Let's take a basic example of a Person. To create a new person and place it in the database, I want the DateOfBirth property to be optional (i.e. NULLable in the DB).

Here's my sample code:

namespace BusinessLayer
{
    class Person
    {
        public string FirstName { get; set; }
        public string L开发者_开发知识库astName { get; set; }
        public DateTime DateOfBirth { get; set; }
    }
}

I'm unsure as to whether the fields should be public or not. Should I do it like this:

class Program
{
    static void Main(string[] args)
    {
        Person person1 = new Person("Kate","Middleton",null);
    }
}

or like this:

class Program
{
    static void Main(string[] args)
    {
        Person person1 = new Person();
        person1.FirstName = "Kate";
        person1.LastName = "Middleton";
    }
}

I'm also wondering how I should be dealing with the optional properties of the class. Once the fields have been populated how do I then save them to the DB? I have a DatabaseComponenet class to save the information. How do I deal with the optional when saving to the database?

So, would I do something like this:

public int Save()
{
    int personId;
    personId = DatabaseComponent.InsertPerson(FirstName, LastName, DateOfBirth);
    return personId;
}

Thanks for any help! Some useful URLs on good class design would also be appreciated.


First, I'd put two distinct public constructor to Person:

namespace BusinessLayer
{
    class Person
    {
        public Person(string firstName, string lastName): this(firstName, lastName, DateTime.Now)
        {}

        public Person(string firstName, string lastName, DateTime birthDate)
        {
            FirstName = firstName;
            LastName = lastName;
            DateOfBirth = birthDate;
        }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime DateOfBirth { get; set; }
    }
}

this allows you to write both

var p = new Person("Marilyin", "Manson");
var p2 = new Person("Alice", "Cooper", new DateTime(...));

and

var p = new Person { FirstName="Marilyn", LastName="Manson" };

I can't see why you should limit to only one form.

As for the DatabaseComponent I'd strongly suggest to write a method that allows you to save a Person instead of the signature you are implicitly declaring.

That's because, should one day change the way a Person is defined, you'd probably have to change the code in each point you invoke Save() method. By saving just a Person, you only have to change the Save() implementation.

Don't you plan to use an ORM by the way?


With C# 3.0 class initializers I no longer bother of providing a constructor that allows me to initialize all properties:

var person1 = new Person
{
    FirstName = "Kate";
    LastName = "Middleton";
};

As far as the Save method is concerned I usually put them in a separate repository class:

public int Save(Person person) 
{
    ...
}

and then when I need to save a person I do:

var person1 = new Person
{
    FirstName = "Kate";
    LastName = "Middleton";
};
var id = new PersonsRepository().Save(person1);


Only use constructors if some fields are mandatory since it's an effective way to make sure that those fields are specified.

I'm unsure as to whether the fields should be public or not

Fields usually means member variables and those should always be private. As for properties I would stick with get/set for database objects.

I'm also wondering how I should be dealing with the optional properties of the class. Once the fields have been populated how do I then save them to the DB?

Saving things to the database is a whole different story. I would not try to invent my own layer but to use an existing one. There are a whole set of different ORM:s out there from very simple to very feature complete.

Take a look at PetaPoco for a lightweight alternative or nHibernate for a more feature complete alternative.

Validation

One common way to make sure that mandatory fields are correctly specified and got valid values are to use a validation framework. There is one built into .net called DataAnnotations. Google it and look at some examples.


This should be checked by using business rules.

I mean if you want a very re-usable business model, business objects should be re-used elsewhere in different areas, and this may mean same class "A" could be fine in state "X" in some business, but in another situation, same class "A", will be fine in state "Y".

There's a good design pattern allowing you to implement business validators called Specification:

  • http://en.wikipedia.org/wiki/Specification_pattern

This can be implemented in a lot of ways, but one of most compact ones is by building rules with lambda expressions.

For example:

someAInstance => someAInstance.Name != null && someAInstance.Age > 30

Another way is using existing object validation libraries, like NHibernate Validator, which can be used standalone without NHibernate and allows you to put attributes in class' properties like [NotNull], [NotNullNotEmpty], and more complex rules, and you can either use built-in ones or you can build your own ones.

Learn more by reading this article (there you'll find a list of out-of-the-box validation rules):

  • http://nhforge.org/wikis/validator/nhibernate-validator-1-0-0-documentation.aspx

Note that one of most important advantages of NH Validator is it can be used in any layer, not only data or business layer, and as you can use it without NHibernate, you've a light-weight, easy-to-use and multi-layered object validator.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜