2010-02-17 2 views
3

Окончательный вопрос: как классы обычно структурированы в приложениях?Классы структурирования

В настоящее время я пишу тестовое банковское приложение в asp.net Например: у меня есть эти два класса. Один представляет собой счет, а другая утилита класса (Он имеет вещи делать со счетами, то есть получение счетов, обновление счетов и т.д.)

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

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

в моем представлении слоя, каждый раз, когда я хочу, чтобы получить учетную запись Я использую:

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

Вы можете видеть, что я создаю новый класс Accounts() для получения учетной записи. Что я должен делать на самом деле? Или это правильно? Соответствует ли статический класс этой потребности лучше?

Я чувствую, что это очень захламлено, и если оно становится больше, оно может быть неконтролируемым классами с похожими именами.

Как вы обычно структурируете это? Вы помещаете эти два метода в класс Учетные записи в класс учетной записи?

Любое понимание здесь было бы так здорово.

Благодаря

ответ

1

Из информации, которую вы должны предоставить мне бы GetAllAccounts и GetAccountByID статические и оставить их в классе счетов. Вы также можете создать статическую функцию для учетных записей, ответственных за создание и извлечение объектов Account. У вашего класса должна быть только одна причина для изменения (принцип единой ответственности).

+0

Благодарим вас за ответ, Guster_Q – Mike

1

Видя Account и Accounts классы меня беспокоят ... Я думаю, что Bank может быть лучшим именем для последнего. Таким образом, у вас есть Банк, который предоставляет доступ ко всем учетным записям или к отдельной учетной записи.

+0

У меня уже есть класс банка. Он имеет информацию, связанную с Банком, а не с счетами в банке. Мой класс Bank имеет свойство для списка ; и у каждого клиента есть Список ; Когда я хочу получить конкретную учетную запись, я вызываю метод класса Accounts GetAccountByID (234); Я надеюсь в этом есть смысл. Это меня тоже немного беспокоит, но я не уверен, что такое лучшая практика: S – Mike

+0

Является ли ваш метод GetAllAccounts методом получения всех учетных записей в «Банке» или все счета для «Клиента»? Если последний, вы можете поместить этот метод в класс 'Client'. –

1

В общем, эти два метода войдут в класс Account. В этом случае нет веских причин иметь два класса. Если вы используете методы «Get», такие как ваш GetAccountByID, они должны быть установлены как static. Это позволяет их вызывать без создания экземпляра нового объекта учетной записи.

public static Account GetAccountByID(int AccountID); 

тогда вызов:

Account editAccount = Account.GetAccountByID(234); 
+0

Забываете ли вы DI, я считаю это неотразимой причиной для разделения классов –

+0

В рамках этого вопроса, очевидно, Майк не реализует ничего подобного шаблону DI. В этом случае нет причин иметь два класса. – nbushnell

+0

Спасибо за ваш ответ, nbushnell. Это помогло мне. – Mike

7

Опыт часто лучший гид, когда речь идет о таких вопросах, потому что дизайн API еще больше искусство, чем наука. Есть противоположные силы в игре для каждого класса вы дизайн:

  • С одной стороны, мы хотим, чтобы классы, чтобы быть сплоченными инкапсулированных из связанных данных и поведения.
  • С другой стороны, мы хотим придерживаться Single Responsibility Principle, чтобы избежать God Objects.

В вашем конкретном случае может показаться, что все поведение относится к учетным записям, что является аргументом для инкапсуляции всего этого в один класс.

Однако, по моему личному опыту, я часто считаю важным разделить создание объекта и срок службы от фактических типов. Это позволяет зависимым инъекциям (DI) и контейнерам DI заботиться о жизненном аспекте экземпляров, в то время как классы могут сосредоточиться на инкапсулировании данных и поведения.

В вашем конкретном случае класс Accounts очень похож на репозиторий , который является типом (часто абстрактным), который мы используем для поиска экземпляров в базах данных или другом постоянном хранилище. Они часто лучше моделируются как отдельные типы, чем классы, которые они извлекают.

В заключение обратите внимание, что в OOD вы не должны беспокоиться о взрыве класса. Предпочтительны многие небольшие классы с четкими обязанностями.

+0

Вы избили меня за секунду по шаблону репозитория :-) –

+0

Я отделил все свои объекты от создания и жизни. Все типы, которые у меня есть, то есть учетная запись, заявление, клиент, отличаются от поведения. Классы, заканчивающиеся на 's', говорят мне, что в этом классе есть методы для управления этим объектом. Объект учетной записи имеет только свойства (нет методов или чего-то еще). Думаю, я понимаю, что вы подразумеваете под репозиторием. Как вы понимаете, что они лучше моделируются как отдельные типы? (что я уже описал выше, что вы имеете в виду?) Спасибо за ваш фантастический ответ! – Mike

+0

Разделение данных по поведению - не очень хорошая идея. Это приводит к модели анемичного домена: http://www.martinfowler.com/bliki/AnemicDomainModel.html Это не то, что я имел в виду. Я имел в виду, что часто бывает полезно разделить * как * экземпляры создаются из *, где * они используются. То есть потребитель типа не создает тип, а скорее запрашивает его либо через свой конструктор, либо через абстрактную фабрику. Вы можете просмотреть репозиторий как частный случай абстрактной фабрики. –

2

Вы ищете Repository pattern, который абстрагирует коллекцию объектов домена. Хранилище для вашего домена может выглядеть следующим образом:

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

    Account GetById(int accountId); 

    // Insert and delete, if they apply 

    // Other account-specific queries and operations 
} 

Презентатор бы объявить зависимость от 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); 
    } 
} 

Далее реализовать IAccountRepository однако вам нравится, и все это вместе, когда вы создаете выступающему :

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

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

Это помогает отделить определение операций от их фактической реализации. Он также позволяет вам выбрать, какой репозиторий вы предоставите ведущему, отделив его от реализации.

Гибкость этого подхода обеспечивает большую свободу и лучше подходит для изменения, чем непосредственное создание зависимостей. Это называется шаблоном Dependency Injection.

+0

Этот ответ немного смутил меня. Разве Презентатор отличается от шаблона? или что кроме ASP.NET MVC? – Mike

+0

Это просто класс, который я написал как часть примера. Ваш пример был всего лишь строкой кода, и я хотел показать зависимость конструктора от 'IAccountRepository'. Я выбрал быструю и грязную версию презентатора, потому что вы упомянули о своем слое презентации. Я бы не слишком много читал в этом :-) –

+0

Ну ладно, я понимаю, что вы имеете в виду сейчас. Я не могу представить, как это будет выглядеть в моем приложении. Особенно в приложении ASP.NET для веб-форм с безгражданностью. Я имею в виду, что я предполагаю, что моя страница создает новый объект Presenter = new AccountPresenter (репозиторий IAccountRepository), который я могу использовать для доступа к свойству Presenter.Account, доступ к которому принадлежит моей учетной записи. Хотел бы я увидеть, как это будет работать. Спасибо за отличный ответ! Мне было о чем подумать. – Mike

0

Как классы обычно структурированы в приложениях?

Poorly.

Что важнее выяснить, что именно должно быть статическим и так далее убедившись, что все отношения между различными классами отражают отношения между реальными вещами, которые они моделируют.

Является ли «Счетами» действительно то, что находится в модели вообще? Вам нужен класс для этого? Не могли бы вы просто иметь список учетных записей, а затем использовать на нем операторы запросов? Вместо метода, который получает учетную запись по его идентификатору, вы можете просто иметь список, а затем использовать accountList.First(x=>x.Id == 123). Возможно, это концепция, в которой вам не нужно даже моделировать.

+0

Я думаю, что учетных записей нет в модели. Итак, как вы думаете, эти методы утилиты должны быть в классе Account? Как инкапсулировать все, что связано с учетными записями под одним классом под названием «Учетная запись»? Класс Account мог бы быть создан с использованием баланса, идентификатора и типа, но также имел бы статические методы, например GetAccountByID. Я не хочу просто иметь список учетных записей как список учетных записей, потому что это может быть триллионы на триллионах записей. Может быть, это будет память чахоточная. – Mike

+0

@Mike: если это тот большой, то это, вероятно, в базе данных, и теперь у вас есть еще одна проблема: с какой абстракцией вы разговариваете с базой данных? Одной из причин, по которой мы разработали LINQ, мы сделали так, чтобы операции над списками в памяти и операциями с запросами базы данных выглядели одинаково или идентично. –

Смежные вопросы