tags:

views:

126

answers:

6

Hi,

The ultimate question is: How are classes normally structured in applications?

I am currently writing a test banking application in asp.net For example: I have these two classes. One represents an account, and the other is a utility class (It has stuff to do with accounts, i.e. getting accounts, updating accounts, etc.)

public Account {
  int ID;
  string Name;
  double Balance;
}

public Accounts {
  public List<Account> GetAllAccounts();
  public Account GetAccountByID(int AccountID);
}

in my presentation layer, whenever I want to get an account I am using:

Account editAccount = new Accounts().GetAccountByID(234);

You can see I am instantiating a new Accounts() class to get an account. What should I actually be doing? Or is this correct? Does a static class fit this need better?

I feel like this is getting very cluttered and if it gets bigger it could be uncontrollable with classes having similar names.

How would you normally structure this? Do you put those two methods in the Accounts class into the Account Class?

Any insight here would be so great.

Thanks

A: 

From the information you have provide I would make GetAllAccounts and GetAccountByID static and leave them in the Accounts class. You can also create a static function on Accounts responsible for creating and retrieving Account objects. Your class should have only one reason to change (Single Responsibility Principle).

Guster_Q
Thank you for your answer, Guster_Q
Mike
A: 

Seeing Account and Accounts classes bothers me a bit...I think Bank may be a better name for the latter. That way, you have a Bank that provided access to all accounts, or to a single specific account.

Grant Palin
I have a Bank class already. It has information to do with the Bank, not the accounts in the bank. My Bank class has a property for List<Clients>; and each clients has a List<Account>; When I want to get a particular account, I'm calling the Accounts class's method GetAccountByID(234); I hope this makes sense. It's bothering me a bit too, but I'm not sure what the best practice is :S
Mike
Is your `GetAllAccounts` method intended to get all accounts within the `Bank`, or all accounts for a `Client`? If the latter, you could put that method in the `Client` class.
Grant Palin
A: 

In general the two methods would go in the Account class. There is no compelling reason to have two classes in this case. If you are doing 'Get' methods like your GetAccountByID these should be set as static. Doing this allows them to be called without instantiating a new account object.

 public static Account GetAccountByID(int AccountID); 

then the call:

Account editAccount = Account.GetAccountByID(234); 
nbushnell
Are you forgetting DI, I would consider this a compelling reason for separating the classes
Rohan West
In the scope of this question, clearly, Mike is not implementing anything like a DI pattern. In this case there is no reason to have two classes.
nbushnell
Thank you for your answer, nbushnell. This has helped me.
Mike
+5  A: 

Experience is often the best guide when it comes to such questions, because API design is still more an art than a science. There are opposing forces in play for every class you design:

In your particular case it may seem like all the behavior relates to Accounts, which would be an argument for encapsulating it all into one class.

However, in my personal experience, I often find it valuable to separate object creation and lifetime from the actual types. This allows Dependency Injection (DI) and DI Containers to take care of the lifetime aspect of instances, while the classes can concentrate on encapsulating data and behavior.

In your specific case, the Accounts class looks a lot like a Repository, which is a type (often abstract) that we use to find instances in databases or other persistent storage. They are often better modeled as separate types than the classes they retrieve.

On a final note, in OOD you should not worry about class explosion. Many small classes with distinct responsibilities are preferrable.

Mark Seemann
You beat me by seconds on the repository pattern :-)
Bryan Watts
I have separated all my objects from creation and lifetime. All of the types that I have, i.e. Account, Statement, Client are separate from the behaviors. The Classes ending in 's' are telling me that in that class has methods to manipulate that object. The account object only has properties (no methods or anything else).I think I understand what you mean by a Repository. How do you mean they are better modeled as separate types? (is what I have described above what you mean?)Thanks for your fantastic answer!
Mike
Separating data from behavior is not a good idea. It leads to an Anemic Domain Model: http://www.martinfowler.com/bliki/AnemicDomainModel.html That wasn't what I meant, either. What I meant is that it's often beneficial to separate *how* instances are created from *where* they are used. That is, the consumer of a type doesn't create the type but rather requests it either through its constructor or through an Abstract Factory. You can view a Repository as a special case of an Abstract Factory.
Mark Seemann
Okay, well I have a big case of the Anemic Domain Model. I do come from a data background. I will do some more research, but if you know of any information, or links, or links to good examples, that might help me in my situation, I would be very greatful. Thank you.
Mike
That is really individual. I have always been fond of the original *Design Patterns* book, as well as Martin Fowler's books and Eric Evans' *Domain-Driven Design*. However, many people find them dry, and I'm not sure they fit your 'data background' ;) Stack Overflow has lots of questions (with answers) about good resources for learning all sorts of topics, and you could also ask one yourself. This is a case where I really think you need more than just my perspective :)
Mark Seemann
+2  A: 

You are looking for the Repository pattern, which abstracts a collection of domain objects. A repository for your domain might look like:

public interface IAccountRepository
{
    IList<Account> GetAll();

    Account GetById(int accountId);

    // Insert and delete, if they apply

    // Other account-specific queries and operations
}

A presenter would declare a dependency on an IAccountRepository:

public class EditAccountPresenter
{
    private readonly IEditAccountView _view;
    private readonly IAccountRepository _accounts;

    public EditAccountPresenter(IEditAccountView view, IAccountRepository accounts)
    {
        _view = view;
        _accounts = accounts;

        _view.DataBinding += OnDataBinding;
    }

    private void OnDataBinding(object sender, EventArgs e)
    {
        _view.Account = _accounts.GetById(234);
    }
}

Next, implement IAccountRepository however you like and put it all together when you create the presenter:

var dataContext = new AccountDataContext("...connection string...");

this.Presenter = new EditAccountPresenter(this, new AccountRepository(dataContext));

This helps to decouple the definition of the operations from their actual implementation. It also allows you to choose which repository you give the presenter, decoupling it from the implementation as well.

The flexibility of this approach offers more freedom, and stands up better to change, than directly instantiating dependencies. This is called the Dependency Injection pattern.

Bryan Watts
This answer has confused me a bit. Is the Presenter apart of the pattern? or is that apart of ASP.NET MVC?
Mike
It's just a class I wrote as part of the example. Your example was just a line of code, and I wanted to show a constructor dependency on `IAccountRepository`. I chose a quick and dirty version of a presenter because you mentioned your presentation layer. I wouldn't read too much into it :-)
Bryan Watts
Ah okay, I understand what you mean now. I can't picture how this would look in my application though. Especially in an ASP.NET webforms application with a stateless nature. I mean, I am envisaging that my page is making a new object Presenter = new AccountPresenter(IAccountRepository repository) which I can use to get access to Presenter.Account property, which has my account to access. I wish I could see how this would actually work. Thank you for your great answer! It's given me a lot to think about.
Mike
The view would be your page, which would implement `IEditAccountView`. That interface defines the `Account` property, which is set by the presenter in response to the view being databound. The page creates the presenter in its `Load` handler. In short, the view creates the presenter and maintains a reference to it (someone has to), but the presenter does all the coordination once it has been created.
Bryan Watts
+1  A: 

How are classes normally structured in applications?

Poorly.

What's more important than figuring out exactly what should be static and so on is making sure that all the relationships between the various classes reflect the relationships between the real-world things that they model.

Is "Accounts" really something that is in the model at all? Do you need to have a class for it? Could you just have a list of accounts and then use query operators on it? Instead of a method that gets an account by its ID, you could simply have a list and then use accountList.First(x=>x.Id == 123). Perhaps this is a concept you don't need to even model in the first place.

Eric Lippert
I guess Accounts isn't in the model. So, do you think that these utility methods should be within the Account class? As encapsulating everything to do with Accounts under the one class called "Account"? The Account class would be able to be instantiated with a balance, ID, and Type, but it would also have static methods like GetAccountByID for example.I don't want to just have an accountsList as a list of accounts because it might be trillions upon trillions of records long. Maybe that would be memory consumptive.
Mike
@Mike: if its that big then its probably in a database, and now you have another problem to deal with: what's the abstraction through which you talk to the database? One of the reasons we designed LINQ the way we did was so that operations on lists in memory and operations on database queries look similar or identical.
Eric Lippert