Error: не определено #11234. Несколько слов в защиту шаблона "Анемичная модель предметной области" (Anemic Domain Model). Анемия

Несколько слов в защиту шаблона "Анемичная модель предметной области" (Anemic Domain Model). Анемия

Анемия - English page

Anemia

This web site presents patients" information regarding different types of anemia. It was created in Russia by hematologists - doctors who are dealing with blood diseases
If you have any questions regarding this resource please contact us through e-mail or by phone (+7-495-741-06-41)

If you have anemia, people may say you have tired blood. That"s because anemia — a condition in which there aren"t enough healthy red blood cells to carry adequate oxygen to your tissues — can make you feel tired.

There are many forms of anemia, each with its own cause. Anemia can be temporary or long term, and it can range from mild to severe.

Anemia is a common blood disorder. Women and people with chronic diseases are at increased risk of the condition.

If you suspect you have anemia, see your doctor. Anemia can be a sign of serious illnesses. Treatments for anemia range from taking supplements to undergoing medical procedures. You may be able to prevent some types of anemia by eating a healthy, varied diet.

Symptoms

The main symptom of most types of anemia is fatigue. Other anemia symptoms include:

  • Weakness
  • Pale skin
  • A fast or irregular heartbeat
  • Shortness of breath
  • Chest pain
  • Dizziness
  • Cognitive problems
  • Numbness or coldness in your extremities
  • Headache

Initially, anemia can be so mild it goes unnoticed. But signs and symptoms increase as the condition worsens.

Causes

Blood consists of both a liquid called plasma and cells. Floating within the plasma are three types of blood cells:

  • White blood cells. These blood cells fight infection.
  • Platelets. These blood cells help your blood clot after a cut.
  • Red blood cells (erythrocytes). These blood cells carry oxygen from your lungs, via your bloodstream, to your brain and the other organs and tissues. Your body needs a supply of oxygenated blood to function. Oxygenated blood helps give your body its energy and your skin a healthy glow.

Red blood cells contain hemoglobin — a red, iron-rich protein that gives blood its red color. Hemoglobin enables red blood cells to carry oxygen from your lungs to all parts of your body, and to carry carbon dioxide from other parts of the body to the lungs so that it can be exhaled.

Most blood cells, including red blood cells, are produced regularly in your bone marrow — a red, spongy material found within the cavities of many of your large bones. To produce hemoglobin and red blood cells, your body needs iron, protein and vitamins from the foods you eat.

Anemia is a state in which the number of red blood cells or the hemoglobin in them is below normal. When you"re anemic, your body produces too few healthy red blood cells, loses too many of them or destroys them faster than they can be replaced. As a result, your blood is low on red blood cells to carry oxygen to your tissues — leaving you fatigued. Common types of anemia and their causes include:

    Iron deficiency anemia. This most common form of anemia affects about one in five women, half of pregnant women and 3 percent of men in the United States. The cause is a shortage of the element iron in your body. Your bone marrow needs iron to make hemoglobin. Without adequate iron, your body can"t produce enough hemoglobin for red blood cells. The result is iron deficiency anemia.

    One way your body gets needed iron is when blood cells die — the iron in them is recycled and used to produce new blood cells. So, if you lose blood, you lose iron. Women with heavy periods who lose a lot of blood each month during menstruation are at risk of iron deficiency anemia. Slow, chronic blood loss from a source within the body — such as an ulcer, a colon polyp or even colon cancer — also can lead to iron loss and iron deficiency anemia.

    Your body also gets iron from the foods you eat. An iron-poor diet can lead to this anemia. In pregnant women, a growing fetus can deplete the mother"s store of iron, leading to iron deficiency anemia.

  • Vitamin deficiency anemias. In addition to iron, your body needs folate and vitamin B-12 to produce sufficient numbers of healthy red blood cells. A diet lacking in these and other key nutrients can cause decreased red blood cell production. People who have an intestinal disorder that affects the absorption of nutrients are prone to this type of anemia. Some people are unable to absorb vitamin B-12 for a variety of reasons and develop vitamin B-12 deficiency anemia, which is sometimes called pernicious anemia. Vitamin deficiency anemias fall into a group of anemias called megaloblastic anemias, in which the bone marrow produces large, abnormal red blood cells.
  • Anemia of chronic disease. Certain chronic diseases — such as cancer, rheumatoid arthritis, Crohn"s disease and other chronic inflammatory diseases — can interfere with the production of red blood cells, resulting in chronic anemia. Kidney failure also can be a cause of anemia. The kidneys produce a hormone called erythropoietin, which stimulates your bone marrow to produce red blood cells. A shortage of erythropoietin, which can result from kidney failure or be a side effect of chemotherapy, can result in a shortage of red blood cells.
  • Aplastic anemia. This is a life-threatening anemia caused by a decrease in the bone marrow"s ability to produce all three types of blood cells — red blood cells, white blood cells and platelets. Many times, the cause of aplastic anemia is unknown, but it"s believed to often be an autoimmune disease. Some factors that can be responsible for this type of anemia include chemotherapy, radiation therapy, environmental toxins, pregnancy and lupus.
  • A variety of diseases, such as leukemia and myelodysplasia, a pre-leukemic condition, can cause anemia by affecting blood production in the bone marrow. The effects of these types of cancer and cancer-like disorders vary from a mild alteration in blood production to a complete, life-threatening shutdown of the blood-making process. Additionally, other cancers of the blood or bone marrow, such as multiple myeloma, myeloproliferative disorders and lymphoma, can cause anemia.
  • Hemolytic anemias. This group of anemias develops when red blood cells are destroyed faster than bone marrow can replace them. Certain blood diseases can cause increased red blood cell destruction. Autoimmune disorders can cause your body to produce antibodies to red blood cells, destroying them prematurely. Certain medications, such as some antibiotics used to treat infections, also can break down red blood cells. Hemolytic anemias may cause yellowing of the skin (jaundice) and an enlarged spleen.
  • Sickle cell anemia. This inherited and sometimes serious anemia, which affects mainly people of African and Arabic descent, is caused by a defective form of hemoglobin that forces red blood cells to assume an abnormal crescent (sickle) shape. These irregular-shaped red blood cells die prematurely, resulting in a chronic shortage of red blood cells. Sickle-shaped red blood cells can also block blood flow through small blood vessels in the body, producing other, often painful, symptoms.
  • Other anemias. There are several other, rarer forms of anemia, such as thalassemia and anemias caused by defective hemoglobin.

Sometimes, no cause of anemia can be identified.

Risk factors

These factors place you at increased risk of anemia:

  • Poor diet. Anyone — young or old — whose diet is consistently low in iron and vitamins, especially folate, is at risk of anemia. Your body needs iron, protein and vitamins to produce sufficient numbers of red blood cells.
  • Intestinal disorders. Having an intestinal disorder that affects the absorption of nutrients in the small intestine — such as Crohn"s disease and celiac disease — puts you at risk of anemia. Surgical removal of or surgery to the parts of the small intestine where nutrients are absorbed can lead to nutrient deficiencies and anemia.
  • Menstruation. In general, women are at greater risk of iron deficiency anemia than are men. That"s because women lose blood — and with it, iron — each month during menstruation.
  • Pregnancy. Pregnant women are at an increased risk of iron deficiency anemia because their iron stores have to serve the increased blood volume of the mother as well as be a source of hemoglobin for the growing fetus.
  • Chronic conditions. For example, if you have cancer, kidney or liver failure, or another chronic condition, you may be at risk of what"s called anemia of chronic disease. These conditions can lead to a shortage of red blood cells. Slow, chronic blood loss from an ulcer or other source within the body can deplete your body"s store of iron, leading to iron deficiency anemia.
  • Family history. If your family has a history of an inherited anemia, you also may be at increased risk of the condition.

Certain infections, blood diseases and autoimmune disorders, exposure to toxic chemicals, and the use of some medications can affect red blood cell production and lead to anemia. Other people at risk of anemia are people with diabetes, people who are dependent on alcohol (alcohol interferes with the absorption of folic acid) and people who adhere to a strict vegetarian diet, who may not get enough iron or vitamin B-12 in their diet.

When to seek medical advice

See your doctor if you"re feeling fatigued for unexplained reasons, especially if you"re at risk of anemia. Some anemias, such as iron deficiency anemia, are common. But don"t assume that if you"re tired, you must be anemic. Fatigue has many causes besides anemia.

Some people learn that their hemoglobin is low, which indicates anemia, when they go to donate blood. Low hemoglobin may be a temporary problem remedied by eating more iron-rich foods or taking a multivitamin containing iron. However, it may also be a warning sign of blood loss in your body that may be causing you to be deficient in iron. If you"re told that you can"t donate blood because of low hemoglobin, ask your doctor if you should be concerned.

If you have a family history of an inherited anemia, such as sickle cell anemia, talk to your doctor and possibly a genetic counselor about your risk and what risks you may pass on to your children.

Tests and diagnosis

Doctors diagnose anemia with the help of a medical history, a physical exam and blood tests, including a complete blood count (CBC). This blood test measures levels of red blood cells and hemoglobin in your blood. Some of your blood may also be examined under a microscope to study the size, shape and color of your red blood cells, which may indicate a diagnosis. For example, in iron deficiency anemia, red blood cells are smaller and paler in color than normal. In vitamin deficiency anemias, red blood cells are enlarged and fewer in number.

If you receive a diagnosis of anemia, your doctor may order additional tests to determine the underlying cause. For example, iron deficiency anemia can result from chronic bleeding of known or unknown ulcers, benign polyps in the colon, colon cancer, tumors, or kidney failure. Your doctor may test for these and other conditions that may underlie the anemia.

Occasionally, it may be necessary to study a sample of your bone marrow to diagnose anemia.

Complications

When anemia is severe enough, it may interfere with your ability to do everyday tasks. You may be too exhausted to work or play. Although anemia is often treatable, it may take several weeks to months for red blood cell levels to return to normal after treatment. Ask your doctor what to expect from treatment.

If you"ve been diagnosed with anemia — it"s often detected during routine blood tests — ask your doctor what treatment is necessary. Then be sure to follow through on treatment, even if you quickly start to feel better. Left unchecked, anemia can lead to a rapid or irregular heartbeat — an arrhythmia. Your heart must pump more blood to compensate for the lack of oxygen in the blood when you"re anemic. This can even lead to congestive heart failure. Untreated pernicious anemia can lead to nerve damage and decreased mental function, as vitamin B-12 is important not only for healthy red blood cells but also for optimal nerve and brain function.

Some inherited anemias, such as sickle cell anemia, can be serious and lead to life-threatening complications. Losing a lot of blood quickly results in acute, severe anemia and can be fatal.

Treatments and drugs

Anemia treatment depends on the cause:

  • Iron deficiency anemia. This form of anemia is treated with iron supplements, which you may need to take for several months or longer. If the underlying cause of iron deficiency is loss of blood — other than from menstruation — the source of the bleeding must be located and stopped. This may involve surgery.
  • Vitamin deficiency anemias. Pernicious anemia is treated with injections — often lifetime injections — of vitamin B-12. Folic acid deficiency anemia is treated with folic acid supplements.
  • Anemia of chronic disease. There"s no specific treatment for this type of anemia. Doctors focus on treating the underlying disease. Iron supplements and vitamins generally don"t help this type of anemia. However, if symptoms become severe, a blood transfusion or injections of synthetic erythropoietin, a hormone normally produced by the kidneys, may help stimulate red blood cell production and ease fatigue.
  • Aplastic anemia. Treatment for this serious anemia may include blood transfusions to boost levels of red blood cells. You may need a bone marrow transplant if your bone marrow is diseased and can"t make healthy blood cells. You may need immune-suppressing medications to lessen your immune system"s response and give the transplanted bone marrow a chance to start functioning again.
  • Anemias associated with bone marrow disease. Treatment of these various diseases can range from simple medication to chemotherapy to bone marrow transplantation. Treatment of these types of anemia usually involves a consultation from a blood specialist (hematologist).
  • Hemolytic anemias. Managing hemolytic anemias includes avoiding suspect medications, treating related infections and taking drugs that suppress your immune system, which may be attacking your red blood cells. Short courses of treatment with steroids or gamma globulin can help suppress your immune system"s attack on your red blood cells. If the condition has caused an enlarged spleen, you may need to have your spleen removed. The spleen — a small organ below your rib cage on the left side — filters out and stores defective red blood cells. Certain hemolytic anemias can cause the spleen to become enlarged with damaged red blood cells.
  • Sickle cell anemia. Treatment for this incurable anemia may include the administration of oxygen, pain-relieving drugs, and oral and intravenous fluids to reduce pain and prevent complications. Doctors also commonly use blood transfusions, folic acid supplements and antibiotics. A bone marrow transplant may be an effective treatment in some circumstances. A cancer drug called hydroxyurea (Droxia, Hydrea) also is used to treat sickle cell anemia in adults.

Prevention

Many types of anemia can"t be prevented. However, you can help avoid iron deficiency anemia and vitamin deficiency anemias by eating a healthy, varied diet that includes foods rich in iron, folate and vitamin B-12.

The best sources of iron are beef and other meats. Other foods rich in iron include beans, lentils, iron-fortified cereals, dark green leafy vegetables, dried fruit, nuts and seeds. Folate, and its synthetic form, folic acid, can be found in citrus juices and fruits, dark green leafy vegetables, legumes and fortified breakfast cereals. Vitamin B-12 is plentiful in meat and dairy products. Foods containing vitamin C, such as citrus fruits, help increase iron absorption.

Eating plenty of iron-containing foods is particularly important for people who have high iron requirements, such as children — iron is needed during growth spurts — and pregnant and menstruating women. Adequate iron intake is also crucial for infants, strict vegetarians and long-distance runners.

Doctors may prescribe iron supplements or multivitamins containing iron for people with high iron requirements. But iron supplements are appropriate only when you need more iron than a balanced diet can provide. Don"t assume that if you"re tired that you simply need to take iron supplements. Overloading your body with iron can be dangerous.

Information from mayoclinic was used in preparation of this page

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

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

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

Классификация анемий
Классификация анемий проводится по ряду показателей.

1). По механизму развития:

1) анемии вследствие кровопотерь (постгеморрагические);

2) анемии вследствие усиленного кроверазрушения (гемолитические);

3) анемии вследствие нарушенного кровообразования, которые в свою очередь делятся на:

а) железодефицитные;

б) порфиринодефицитные;

в) В12 фолиево-дефицитные;

г) гипо-, апластические и метапластические.

2). По типу кроветворения:

1) нормобластические;

2) мегалобластические.

3). По цветовому показателю, важнейшему дифференциально-диагностическому критерию:

1) нормохромные, когда цветовой показатель равен 0,82-1,05;

2) гипохромные, если цветовой показатель меньше 0,82;

3) гиперхромные, когда цветовой показатель выше 1, 05.

К нормохромным анемиям относятся острая постгеморрагическая анемия в стадии гидремической компенсации, некоторые формы гемолитической анемии , особенно приобретенные. Гипо- и апластические анемии , как правило, являются нормохромными.

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

Снижение цветового показателя является результатом либо уменьшения среднего размера эритроцитов, либо недостаточного их насыщения гемоглобином в связи с нарушением синтеза последнего. Причиной гипохромии может быть также периферический ретикулоцитоз, так как на стадии ретикулоцита синтез гемоглобина еще не завершен. Его синтез и накопление в ретикулоцитах продолжается до полного их созревания, поэтому регенераторные и гиперрегенераторные анемии , сопровождающиеся увеличением количества ретикулоцитов, бывают гипохромными.

Повышение цветового показателя возникает в тех случаях, когда увеличивается средний диаметр эритроцитов. Особенно резкое увеличение размеров красных кровяных клеток имеет место при мегалобластическом типе эритропоэза. Вот почему В12-фолиево-дефицитные анемии являются гиперхромными.

4). По размеру эритроцитов:

1) нормоцитарные (с нормальным средним диаметром эритроцитов 7,2-8,0 мк);

2) микроцитарные (средний диаметр эритроцитов ниже 7,2 мк);

3) макроцитарные (диаметр эритроцитов более 8 мк).

В группу макроцитарных анемий входят и мегалоцитарные анемии , при которых средний диаметр эритроцитов превышает 9,0 мкм.

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

Микроцитарными анемиями являются железодефицитная, порфириндефицитная анемии , талассемия, микросфероцитарная болезнь Миньковского - Шоффара.

Макроцитарные анемии делятся на мегалобластные и немегалобластные, Мегалобластными макроцитарными анемиями являются В12-фолиево-дефицитная анемия , анемия после длительного употребления лекарственных препаратов, нарушающих синтез ДНК. К немегалобластным макроцитарным анемиям относятся анемии, сочетающиеся с болезнями печени, гипотиреозом. Макроцитарный характер могут приобретать аутоиммунная гемолитическая анемия , ночная пароксизмальная гемолобинурия, гемолитические анемии после криза, апластические анемии, анемии при опухолях желудочно-кишечного тракта и кроветворной системы, нередко на фоне лечения цитостатическими препаратами.

5) По регенераторной активности костного мозга, определяемой на основании содержания ретикулоцитов в периферической крови, выделяют анемии :

1) регенераторные, с достаточной функцией костного мозга. Число ретикулоцитов в периферической крови в пределах 1,0-5,0 %;

2) гипорегенераторные, с пониженной регенераторной функцией костного мозга. Количество ретикулоцитов в периферической крови меньше 0,2 %;

3) гиперрегенераторные, с повышенной регенераторной функцией костного мозга. Количество ретикулоцитов в периферической крови превышает 5,0 %;

4) арегенераторные, с резким угнетением эритропоэза. Ретикулоциты в периферической крови, как правило, не определяются.

От переводчика: На проекте, где я работаю, сейчас идет активное переписывание логики, ранее реализованной в виде богатой модели предметной области (с использованием Active Record и Unit of Work). Новый подход включает в себя классы сущностей без поведения и служб без состояния, взаимодействующих посредством интерфейсов - фактически, он представляет собой анемичную модель, с перспективой перехода в дальнейшем на микросервисную архитектуру. Наблюдая в режиме реального времени, как «макаронный монстр» из примерно полутора миллионов LOC постепенно обретает форму, как упрощаются тестирование, масштабирование и кастомизация системы под нуждый различных заказчиков, я был весьма удивлен, узнав, что такой подход часто рассматривается как архитектурный анти-шаблон. Пытаясь разобраться в причинах этого, я наткнулся на данную статью и размещаю здесь ее перевод, чтобы обсудить с сообществом плюсы и минусы подхода.

Шаблоны проектирования, анти-шаблоны и анемичная модель предметной области

Говоря об объектно-ориентированной разработке программного обеспечения, под шаблонами проектирования понимают повторяющиеся и эффективные способы решения часто возникающих проблем. Благодаря формализации и описанию таких шаблонов разработчики получают набор «проверенных в бою» архитектурных решений для определенных классов проблем, а также общий словарь для их описания, понятный другим разработчикам. Первым этот термин ввел Эрих Гамма в своей книге «Приемы объектно-ориентированного проектирования. Паттерны проектирования» , где он описал несколько часто применяемых шаблонов. По мере того как новое понятие набирало популярность, словарь шаблонов проектирования пополнялся (, ).


Вслед за ростом популярности концепции паттернов проектирования в обиход была введена идея «анти-шаблонов» (, ). Как ясно из самого названия, анти-шаблон - это противоположность шаблона. Он тоже описывает повторяющийся способ решения часто возникающей проблемы, однако, как правило, это решение нерабочее или неэффективное, оказывающее негативное влияние на «здоровье» системы (в плане простоты поддержки, расширяемости, надежности и т.д.). Анти-шаблоны служат тем же целям, что и шаблоны: при описании анти-шаблона показывают типичные варианты реализации, раскрывают контекст, в котором он применяется, и объясняют, к каким проблемам в разрабатываемом ПО это приводит.


Но концепция анти-шаблонов имеет свой недостаток: снижение критичности восприятия в вопросе применимости того или иного шаблона. Архитектурные решения, неприменимые в одной ситуации, могут оказаться разумным выбором в другой, однако, если решение признано анти-шаблоном, оно может быть отвергнуто без обсуждения, даже если на самом деле оно вполне подходило для решаемой задачи.


Я убежден, что одним из таких незаслуженно отвергаемых анти-шаблонов является Анемичная модель предметной области (АМПО, Anaemic Domain Model), описанная Мартином Фаулером и Эриком Эвансом . Оба автора описывают этот шаблон как неспособность смоделировать предметную область в объектно-ориентированном стиле, из-за чего бизнес-логика описывается в процедурном стиле. Такой подход противопоставляется Богатой модели предметной области (БМПО, Rich Domain Model) , - в ней классы, представляющие сущности предметной области, содержат в себе и данные, и всю бизнес-логику. Да, анемичная модель может быть неудачным выбором для некоторых систем, но совершенно не факт, что то же самое справедливо для любых систем. В этой статье я рассматриваю аргументы, выдвигаемые против анемичной модели, и обосновываю, почему в ряде сценариев АМПО выглядит разумным выбором с точки зрения соответствия принципам SOLID, сформулированным Робертом Мартином (, ), - принципам, в которых заключены рекомендации по достижению баланса между простотой, масштабируемостью и надежностью при разработке ПО. Решая гипотетическую проблему и сравнивая анемичную и богатую модели, я намерен показать, что АМПО лучше соответствует приципам SOLID. Тем самым я хочу оспорить категоричное мнение об этом подходе, навязанное авторитетами, и показать, что использование АМПО - на самом деле, годное архитектурное решение.

Почему анемичную модель предметной области считают анти-шаблоном?

Фаулер и Эванс описывали АМПО как совокупность классов без поведения, содержащих данные, необходимые для моделирования предметной области. В этих классах практически нет (или нет вовсе) логики по валидации данных на соответствие бизнес-правилам. Вместо этого, бизнес-логика заключена в слое служб, который состоит из типов и функций, обрабатывающих элементы модели в соответствии с бизнес-правилами. Основной аргумент против такого подхода состоит в том, что данные и способы их обработки оказываются разделены, что нарушает один из фундаментальных принципов объектно-ориентированного подхода, т.к. не позволяет модели обеспечивать собственные инварианты. В противоположность этому, хотя БМПО и состоит из того же набора типов, содержащих данные о предметной области, - но вся бизнес-логика также заключена в этих сущностях, будучи реализованной в виде методов классов. Таким образом, БМПО хорошо согласуется с принципами инкапсуляции и сокрытия информации. Как было отмечено Майклом Скоттом в : «Благодаря инкапсуляции, разработчики могут объединять данные и операции по их обработке в одном месте, а также скрывать ненужные детали от пользователей обобщенной модели».


В БМПО слой служб чрезвычайно тонок, а иногда и вовсе отсутствует , и все правила, относящиеся к предметной области, реализуются посредством модели. Тем самым утверждается, что сущности предметной области способны полностью самостоятельно обеспечивать свои инварианты, что делает такую модель полноценной с точки зрения объектно-ориентированного подхода.


Не нужно забывать, однако, что способность модели обеспечивать выполнение определенных ограничений, налагаемых на данные, - это лишь одно из множества свойств, которыми должна обладать система. Пусть АМПО жертвует возможностью валидации на уровне отдельных бизнес-сущностей, но взамен она дает невероятную гибкость и простоту поддержки системы в целом, благодаря тому, что реализация логики вынесена в узкоспециализированные классы, а доступ к ним осуществляется через интерфейсы. Эти преимущества имеют особенно большое значение в языках со статической типизацией, таких как Java или C# (в которых поведение класса не может быть изменено во время исполнения программы), т.к. улучшают тестируемость системы путем введения явных «швов» (, ) с целью устранения чрезмерной связанности.

Простой пример

Давайте представим серверную часть интернет-магазина, где клиент может как покупать товары, так и выставлять на продажу товары для других клиентов со всего земного шара. Приобретение товара приводит к уменьшению средств на счету покупателя. Подумаем, как можно реализовать процесс размещения клиентом заказа на приобретение товара. Согласно требованиям, клиент может разместить заказ, если у него а) достаточно средств на счету, и б) товар доступен в регионе клиента. При использовании БМПО, класс Customer будет описывать сущность «Клиент»; он будет включать все свойства клиента и такие методы как PurchaseItem(Item item) (Купить товар). Аналогично, классы Item и Order представляют модели предметной области, описывающие сущности Товар и Заказ, соответственно. Реализация класса Customer (на псевдо-C#) может быть примерно такой:


/*** КОД С ИСПОЛЬЗОВАНИЕ БМПО ***/ class Customer: DomainEntity // Базовый класс, предоставляющий CRUD-операции { // Опускаем объявление закрытых членов класса public bool IsItemPurchasable(Item item) { bool shippable = item.ShipsToRegion(this.Region); return this.Funds >= item.Cost && shippable; } public void PurchaseItem(Item item) { if (IsItemPurchasable(item)) { Order order = new Order(this, item); order.Update(); this.Funds -= item.Cost; this.Update(); } } } /*** КОНЕЦ КОДА С ИСПОЛЬЗОВАНИЕ БМПО ***/

Сущности предметной области реализуются с использованием шаблона Active Record , в котором используются методы Create/Read/Update/Delete (реализованные на уровне фреймворка или базового класса), позволяющие изменять записи в слое хранения данных (например, в базе данных). Предполагается, что метод PurchaseItem вызывается в рамках транзакции, совершаемой над хранилищем данных и управляемой извне (например, она может открываться в обработчике HTTP-запроса, который извлекает информацию о клиенте и товаре непосредственно из переданных в запросе параметров). Получается, что в нашей БМПО роль сущности «Клиент» состоит 1) в представлении модели данных, 2) реализации бизнес-правил, 3) создании сущности «Заказ» для совершения покупки и 4) взаимодействии со слоем хранения данных посредством методов, определенных для Active Record. Воистину, «богатству» такой модели позавидовал бы царь Крез, а мы ведь рассматривали довольно простой вариант использования.


Следующий пример иллюстрирует, как та же логика могла бы быть выражена средствами АМПО, в тех же условиях:


/*** КОД С ИСПОЛЬЗОВАНИЕМ АМПО ***/ class Customer { /* Some public properties */ } class Item { /* Some public properties */ } class IsItemPurchasableService: IIsItemPurchasableService { IItemShippingRegionService shipsToRegionService; public bool IsItemPurchasable(Customer customer, Item item) { bool shippable = shipsToRegionService.ShipsToRegion(item); return customer.Funds >= item.Cost && shippable; } } class PurchaseService: IPurchaseService { ICustomerRepository customers; IOrderFactory orderFactory; IOrderRepository orders; IIsItemPurchasableService isItemPurchasableService; // Конкретные экземпляры инициализируются в конструкторе public void PurchaseItem(Customer customer, Item item) { if (isItemPurchasableService.IsItemPurchasable(customer, item)) { Order order = orderFactory.CreateOrder(customer, item); orders.Insert(order); customer.Balance -= item.Cost; customers.Update(customer); } } } /*** КОНЕЦ КОДА С ИСПОЛЬЗОВАНИЕМ АМПО ***/

Сравнение примеров реализации с точки зрения соответствия принципам SOLID

На первый взгляд, АМПО явно проигрывает БМПО. В ее реализации использовано больше классов, а логика размазана по двум доменным службам (IPurchaseService и IItemPurchasableService ) и ряду служб приложения (IOrderFactory , ICustomerRepository и IOrderRepository ), вместо того чтобы располагаться в пределах модели предметной области. Классы предметной области теперь не содержат никакого поведения, а всего лишь хранят данные и допускают изменение своего состояния вне рамок наложенных ограничений (и - о ужас! - утрачивают способность обеспечивать собственные инварианты). Учитывая все эти явные недостатки, как вообще можно рассматривать такую модель как конкурента куда более объектно-ориентированной БМПО?


Причины, по которым АМПО является превосходным выбором для данного сценария, проистекают из рассмотрения принципов SOLID и их наложения на обе рассматриваемые архитектуры . «S» означает «Принцип единственной ответственности» (Single Responsibility Pronciple, ), который гласит, что класс должен делать только что-то одно - но делать это хорошо. В частности, класс должен реализовывать лишь одну абстракцию. «O» - «Принцип открытости/закрытости» (Open/Closed Principle, ), постулат о том, что класс должен быть «открытым для расширения, но закрытым для изменения». Это означает, что при разработке класса надо максимально стремиться к тому, чтобы реализацию не пришлось изменять в будущем, тем самым сводя к минимуму последствия вносимых изменений.


Казалось бы, класс Customer в БМПО реализует единственную абстракцию «Клиент», но на самом деле этот класс отвечает за множество вещей. Этот класс моделирует и данные, и логику в рамках одной и той же абстракции, несмотря на то, что бизнес-логика имеет обыкновение меняться куда чаще, чем структура данных. Этот же класс создает и инициализирует сущности «Заказ» в момент совершения покупки, и даже содержит логику, определяющую, может ли клиент совершить покупку. А предоставляя базовые CRUD-операции, определенные в базовом классе, сущность предметной области «Клиент» оказывается еще и связанной с той моделью хранилища данных, которая поддерживается базовым классом. Стоило нам перечислить все эти обязанности, как стало очевидным, что сущность Customer в БМПО являет собой пример слабого разделения ответственности.


Анемичная модель наоборот разделяет зоны ответственности таким образом, что каждый компонент представляет единственную абстракцию. Данные из предметной области представлены в виде «плоских» структур данных , тогда как бизнес-правила и чисто инфраструктурные задачи (сохранение, создание новых экземпляров объектов и т.п.) заключены в отдельных службах (и доступны посредством абстрактных интерфейсов). Как следствие, связанность классов уменьшается.

Сравнение гибкости решений на базе богатой и анемичной моделей предметной области

Рассмотрим примеры сценариев, при которых нам пришлось бы изменять класс Customer в БМПО.

  • Необходимо добавить новое поле (или изменить тип данных существующего).
  • В конструктор класса Order необходимо передать дополнительный параметр.
  • Бизнес-логика, относящаяся к покупке товара, усложнилась.
  • Возникла необходимость сохранения данных в альтернативное хранилище, которое не поддерживается нашим гипотетическим базовым классом DomainEntity.

Теперь рассмотрим сценарии, в которых нам необходимо изменить типы, описанные в АМПО. Классы бизнес-сущностей, чье предназначение состоит в моделировании предметной области, подлежат изменению тогда и только тогда, когда изменяются требования к составу данных. В случае усложнения правил, по которым определяется возможность приобретения того или иного товара (например, для товара указывается минимально допустимый «рейтинг доверия» клиента, которому этот товар может быть продан), изменению подлежит только реализация IIsItemPurchasableService , в то время как при использовании БМПО нам пришлось бы соответствующим образом изменять класс Customer . Если меняются требования к хранилищу данных - в АМПО задача решается путем передачи в PurchaseService из вышестоящего класса служб приложения новой реализации существующего интерфейса репозитория , , не требуя модификации существующего кода; в БМПО так легко не отделаться, модификация базового класса затронет все классы бизнес-сущностей, унаследованных от него. В случае, когда для создания экземпляра класса Order необходимо передать дополнительный параметр, реализация IOrderFactory может оказаться в состоянии обеспечить это изменение, не оказывая влияния на PurchaseService . В анемичной модели у каждого класса единственная ответственность, и вносить изменения в класс придется только при изменении соответствующего требования в предметной области (или связанной инфраструктуре).


А сейчас представим, что для реализации нового бизнес-требования мы должны обеспечить возможность возврата средств, если клиент не удовлетворен покупкой. В богатой модели это можно было бы реализовать путем добавления метода RefundItem к сущности «Клиент», аргументируя это тем, что вся логика, относящаяся к клиенту, оказывается заключенной в сущности Customer . Однако процедура возврата денежных средств сильно отличается от процедуры совершения покупки, ответственность за которую ранее была возложена на класс Customer , и в результате мы получаем еще большее смешение ответственностей в пределах одного типа. Выходит, в классах богатой модели могут накапливаться слабо связанные элементы бизнес-логики, повышая сложность их структуры. В анемичной модели механизм возврата денежных средств можно реализовать путем создания нового класса RefundService , который будет реализовывать только логику, непосредственно относящуюся к возвратам. Этот класс может зависеть от нескольких других абстракций (т.е. интерфейсов других доменных и инфраструктурных служб), необходимых для выполнения им своих обязанностей. Обращение к методам класса RefundService может происходить из вышележащих уровней (в ответ на запрос об осуществлении возврата денежных средств), и выходит, что реализацию нового сценария удалось выполнить безо всякого влияния на ранее разработанную функциональность.


В рассмотренном примере проблема закрепления за одним классом не связанных между собой ответственностей, с которой мы столкнулись в БМПО, эффективно решается в анемичной модели при помощи букв I и D из аббревиатуры SOLID. Это, я напомню, «Принцип разделения интерфейса» (Interface Segregation Principle, ) и «Принцип инверсии зависимостей» (Dependency Inversion Principle, ). Они утверждают, что интерфейсы должны представлять собой наборы сильно сцепленных методов, и что интерфейсы должны использоваться для соединения частей системы воедино (в случае АМПО - соединение служб доменного слоя между собой). Следование принципу разделения интерфейса, как правило, дает в результате небольшие, узкоспециализированные интерфейсы - такие как IItemShippingRegionService и IIsItemPurchasableService из нашего примера, или интерфейс абстрактного репозитория. Принцип инверсии зависимостей заставляет нас опираться на эти интерфейсы, чтобы одна служба не зависела от деталей реализации другой.

Анемичная модель предметной области лучше поддерживает автоматизированное тестирование

Более гибкая и податливая структура приложения, а также следование вышеупомянутым принципам, позволяют анемичной модели проявить свои преимущества над БМПО в упрощении автоматизированного тестирования. Сильно сцепленные, но слабо связанные между собой компоненты общаются посредством интерфейсов и собираются воедино посредством внедрения зависимостей, что позволяет без особого труда подменять зависимости «пустышками», mock-объектами. Отсюда, в АМПО несложно реализовывать такие сценарии для автоматизированного тестирования, которые было бы гораздо труднее реализовать в рамках БМПО, тем самым улучшается простота поддержки автоматизированных тестов. При снижении «стоимости» автоматизированных тестов разработчики более охотно создают и поддерживают их в актуальном состоянии. В качестве иллюстрации, попробуем разработать модульный тест для метода IsItemPurchasable .


Согласно предъявленным требованиям, товар считается доступным для покупки, если у клиента достаточно средств на счету, и он находится в регионе, куда этот товар может быть доставлен. Положим, мы пишем тест, проверяющий, что если у клиента достаточно средств на счету, но он не находится в регионе, куда осуществляется доставка данного товара, то этот товар недоступен для покупки. В БМПО такой тест, вероятно, включал бы создание экземпляров Клиент (Customer ) и Товар (Item ), настройку Клиента таким образом, чтобы средства на его счету превышали стоимость Товара, и чтобы его регион не входил в перечень регионов, куда этот товар доставляется. После чего мы должны были бы убедиться, что customer.IsItemPurchasable(item) возвращает значение false . Однако метод IsItemPurchasable зависит от деталей реализации метода ShipsToRegion класса Item . Изменение бизнес-логики, относящейся к товару, приведет к изменению результатов этого теста. Такой эффект нежелателен, так как данный тест должен проверять исключительно логику, заключенную в классе Customer , а логика метода ShipsToRegion , заключенная в сущности «Товар», должна покрываться отдельным тестом. Поскольку бизнес-логика заключена в сущностях, описывающих предметную область и предоставляющих открытый интерфейс для доступа к заключенной в них логике, классы оказываются сильно связанными, что приводит к лавинообразному эффекту при внесении изменений, из-за чего автоматизированные тесты становятся хрупкими.


С другой стороны, в АМПО логика метода IsItemPurchasable вынесена в отдельную специализированную службу, которая зависит от абстрактных интерфейсов (метод IItemShippingRegionService.ShipsToRegion ). Для рассматриваемого теста мы можем попросту создать заглушку для IItemShippingRegionService , в которой будет реализован метод ShipsToRegion , всегда возвращающий false . Разделив бизнес-логику по изолированным модулям, мы защитили каждую часть от изменений деталей реализации в других частях. На практике это означает, что небольшое изменение логики скорее всего приведет к «падению» лишь тех тестов, которые непосредственно проверяют поведение того кода, в который были внесены изменения, что можно использовать для проверки правильности нашего представления об изменяемом коде.

Рефакторинг БМПО с целью соблюдения принципов SOLID приводит к «анемии» модели

Сторонники архитектуры, использующей БМПО, могут возразить, что описанный гипотетический пример не соответствует «истинной» богатой модели. Они скажут, что в правильно реализованной богатой модели нельзя смешивать сущности предметной области с задачами по их записи в хранилище - вместо этого предпочтительнее использовать объекты передачи данных (DTO, Data Transfer Object, , ), посредством которых происходит обмен со слоем хранения данных. Они разнесут в пух и прах идею прямого вызова конструктора класса Order непосредственно из логики класса Customer - разумеется, ни в одной вменяемой реализации сущности предметной области не будут вызывать конструктор напрямую, здравый смысл заставляет использовать фабрику ! Но по мне, это выглядит как попытка применять мощь принципов SOLID к инфраструктурным службам, при полном их игнорировании в приложении к модели предметной области. Если нашу гипотетическую БМПО рефакторить для соответствия принципам SOLID, будут выделены более мелкие сущности: из сущности Клиент могут быть выделены сущности «Покупка клиента» (CustomerPurchase ) и «Возврат ден.средств клиента» (CustomerRefund ). Но может статься, что и новые модели будут по-прежнему зависеть от элементарных бизнес-правил, изменяемых независимо друг от друга, а от них, в свою очередь, будут зависеть другие сущности. Во избежание дублирования логики и сильной связанности классов эти правила придется и дальше рефакторить, выделяя их в отдельные модули, доступ к которым осуществляется посредством интерфейсов. В итоге, богатая модель, отрефакторенная до полного соответствия принципам SOLID, стремится к состоянию анемичной модели!

Заключение

Исследовав реализацию простого примера, мы пришли к выводу, что анемичная модель предметной области ближе соответствует принципам SOLID, чем богатая модель. Мы увидели преимущества, которые дает соответствие принципам SOLID: слабую связанность и сильную сцепленность, повышающие гибкость архитектуры приложения. Свидетельством возросшей гибкости явилось улучшение тестируемости приложения из-за легкости реализации «заглушек» для зависимостей. Рассматривая пути достижения этих же качеств в рамках БМПО, мы обнаружили, что рефакторинг богатой модели закономерно приводит к ее «анемичности».


Таким образом, если соответствие принципам SOLID является признаком хорошо структурированного объектно-ориентированного приложения, а анемичная модель ближе соответствует этим принципам, чем богатая модель, то анемичную модель не следует считать анти-шаблоном; ее надлежит рассматривать как жизнеспособный вариант архитектуры при моделировании предметной области.

Ссылки

Развернуть

Evans, Eric. Domain-driven design: tackling complexity in the heart of software. Addison-Wesley Professional, 2004.


Martin, Robert C. The Principles of Object-Oriented Design. http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod , 2005.


Martin, Robert C. Design principles and design patterns. Object Mentor, 2000: 1-34.


Erich, Gamma, et al. Design patterns: elements of reusable object-oriented software. Addison Wesley Publishing Company, 1994.


Wolfgang, Pree. Design patterns for object-oriented software development. Addison-Wesley, 1994.


Rising, Linda. The patterns handbook: techniques, strategies, and applications. Vol. 13. Cambridge University Press, 1998.


Budgen, David. Software design. Pearson Education, 2003.


Scott, Michael L. Programming language pragmatics. Morgan Kaufmann, 2000.


Hevery, Miško. Writing Testable Code. http://googletesting.blogspot.co.uk/2008/08/by-miko-hevery-so-you-decided-to.html , Google Testing Blog, 2008.


Osherove, Roy. The Art of Unit Testing: With Examples in. Net. Manning Publications Co., 2009.


Martin, Robert C. Agile software development: principles, patterns, and practices. Prentice Hall PTR, 2003.


Martin, Robert C. SRP: The Single Responsibility Principle. , Object Mentor, 1996.


Martin, Robert C. The Open-Closed Principle. , Object Mentor, 1996.


Martin, Robert C. The Interface Segregation Principle. , Object Mentor, 1996.


Martin, Robert C. The Dependency Inversion Principle, Object Mentor, 1996.


Fowler, Martin. Patterns of enterprise application architecture. Addison-Wesley Longman Publishing Co., Inc., 2002.


Fowler, Martin. Data Transfer Object. http://martinfowler.com/eaaCatalog/dataTransferObject.html , Martin Fowler site, 2002.

Анемичная доменная модель

Если ваши доменные объекты являются контейнерами данных и всё, что в них есть, это свойства get/set , то вы используете анемичную доменную модель . Её особенностью является то, что доменный объект не имеет поведения.

Задача

Сценарии использования, к примеру, интернет-магазина:

  1. Пользователь, который зарегистрировался в системе, получает письмо со ссылкой на подтверждение регистрации. Перейдя по ссылке, он подтверждает свою регистрацию и может заходить под своим логином и паролем в систему.
  2. Пользователь может делать заказы
  3. При этом в личном кабинете он видит общую сумму, на которую заказал. В общей сумме текущих заказов не учитываются уже завершенные заказы

Начнем с анемичной модели данных. У нас будет класс Account :

Public class Account { public int Id { get; set; } public bool IsApproved { get; set; } public DateTime? ActivationDate { get; set; } public List Orders { get; set; } }

И класс Order :

Public class Order { public int Id { get; set; } public int Price { get; set; } public Account Account { get; set; } public bool IsComplete { get; set; } }

Реализация

Каждый из сценариев работы довольно просто реализовать:

Сценарий №1. Активация пользователя

Account.ActivationDate = DateTime.Now; account.IsApproved = true;

Сценарий №2. Добавление заказа

Account.Orders.Add(order); order.Account = account;

Сценарий №3. Подсчёт общей суммы

Account.Orders .Where(order => order.IsComplete == false) .Sum(order => order.Price);

Главный вопрос: где будет располагаться этот код?

Решение №0

Есть самое простое и неправильное решение. Мы будем писать этот код прямо в обработчиках на aspx -страницах или WinForms:

Public partial class Default: Page { protected void Page_Load(object sender, EventArgs e) { // выборка объекта account AccountOrdersSumLabel.Text = account.Orders .Where(order => order.IsComplete == false) .Sum(order => order.Price); } protected void AddOrderButton_Click(object sender, EventArgs e) { // выборка объекта account account.Orders.Add(order); order.Account = account; // сохранение объекта account } }

Все будет хорошо, пока добавлять продукт можно только из этой формы, а подсчёт общей суммы происходит только по этой формуле. Проблемы начнутся, когда на другой форме потребуется такая же функциональность. Придется дублировать код. Тогда, при изменении логики работы, придется исправлять её во всех code-behind"ах.

Глупо дублировать код, а потом тратить много времени на исправление одного изменившегося бизнес-требования.

Решение №1

Все-таки дублировать не будем. Мы вынесем код реализации наших сценариев в класс со звучным названием AccountHelper или AccountManager . Скорее всего этот класс будет без состояния, а потому статическим.

Получаем:

Public static class AccountHelper { public static void Activate(Account account) { account.ActivationDate = DateTime.Now; account.IsApproved = true; } public static void AddOrder(Account account, Order order) { account.Orders.Add(order); order.Account = account; } public static int CalculateOrdersSum(Account account) { return account.Orders .Where(order => order.IsComplete == false) .Sum(order => order.Price); } }

Проблема классов с названием *Helper или *Manager в том, что они могут себе позволить делать всё, что угодно. Их абстрактные названия позволяют «помогать» классу Account делать абсолютно разные вещи. Такие классы со временем становятся .

У таких классов множество недостатков. Например, трудно тестировать код, который использует эти классы, потому что они статические. Они делают код сильно связаным, т.к. нарушают . Очень часто из одного Helper "а вызывают другие Helper "ы. В итоге, граф зависимостей напоминает паутину из связей.

К тому же, это решение обладает всеми недостатками следующего.

Решение №2

Public interface IAccountService { void Activate(Account account); void AddOrder(Account account, Order order); int CalculateOrdersSum(Account account); } public class AccountService: IAccountService { public void Activate(Account account) { account.ActivationDate = DateTime.Now; account.IsApproved = true; } public void AddOrder(Account account, Order order) { account.Orders.Add(order); order.Account = account; } public int CalculateOrdersSum(Account account) { return account.Orders .Where(order => order.IsComplete == false) .Sum(order => order.Price); } }

Разобрались со связанностью и тестирование. Уже шаг вперёд. Но я вижу ещё две проблемы.

Функций типа AddOrder и CalculateOrdersSum будет довольно много. Через пол года разработки интерфейс IAccountService вырастит до 40-50 функций. «Загрязнение» интерфейса можно было бы пережить, если бы не вторая проблема.

В коде в любом месте можно в обход сервиса написать «свою активацию» пользователя. Например, взять объект Account из базы, выставить ему поле IsApproved в true и при этом забыть обновить поле ActivationDate . Тоже самое касается сценария добавления заказа. Можно вызвать функцию Add у свойства Orders где угодно и забыть выставить поле Account у добавляемого заказа. Это делает систему нестабильной. API приложения беззащитно перед пользователями системы. С таким подходом остается только надеятся, что программист найдёт нужную ему функцию в IAccountService , а не станет изобретать свой подход.

Решение №3

Поместим все эти функции в сам доменный объект Account . Обратите внимание на то, как изменились модификаторы доступа к полям объекта:

Public class Account { private readonly List orders; public Account() { orders = new List(); } public int Id { get; set; } public bool IsApproved { get; private set; } public DateTime? ActivationDate { get; private set; } public IEnumerable Orders { get { return orders; } } public int OrdersSum { get { return Orders .Where(order => order.IsComplete == false) .Sum(order => order.Price); } } public void Activate() { ActivationDate = DateTime.Now; IsApproved = true; } public void AddOrder(Order order) { orders.Add(order); order.Account = this; } }

Теперь домен нашего приложения даёт пользователю готовое API, которое не требудет ни Helper "ов, ни сервисов. К тому же мы уберегаем пользователя от ошибок. Он уже не сможет активировать Account выставив только IsApproved . Теперь функция Activate сама заполнит нужные поля.

Заключение

Итак, если функция оперирует данными и объектами, которые находятся внутри домена, то, скорее всего, надо оставлять эту функцию внутри домена. Кроме надёжности кода, вы в добавок создадите доменный язык для вашего приложения.

Последнее обновление: 19.07.2016

Одним из ключевых компонентов паттерна MVC являются модели . Ключевая задача моделей - описание структуры и логики используемых данных.

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

Все модели оформляются как обычные POCO-классы (plain-old CRL objects), то есть обычные классы на языке C#. Например, если мы работаем с приложением интернет-магазина мобильных телефонов, то мы могли бы определить в проекте следующую модель, представляющую телефон:

Public class Phone { public int Id { get; set; } public string Name { get; set; } public string Company { get; set; } public int Price { get; set; } }

Модель Phone определяет ряд свойств: уникальный идентификатор Id, название, компанию производителя и цену. Это классическая анемичная модель . Анемичная модель не имеет поведения и хранит только состояние в виде свойств.

Однако модель необязательно должна состоять только из свойств. Кроме того, она может иметь конструктор, какие-нибудь методы, поля, вообщем предствлять стандартный класс на языке C#. Модели, которые также определяют поведение, в противоположность анемичным моделям называют "толстыми" моделями (Rich Domain Model / Fat Model / Thick Model). Например, мы можем уйти от анемичной модели, модифицировав ее следующим образом:

Public class Phone { private decimal _discount = 0; public Phone(decimal discount) { this._discount = discount; } public int Id { get; set; } public string Name { get; set; } public string Company { get; set; } public decimal Price { get; set; } public decimal GetPriceWithDiscount() { return this.Price - (this.Price * this._discount); } }

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

В приложении ASP.NET MVC Core модели можно разделить по степени применения на несколько групп:

    Модели, объекты которых хранятся в специальных хранилищах данных (например, в базах данных, файлах xml и т.д.)

    Модели, которые используются для передачи данных представление или наоборот, для получения данных из представления. Такие модели еще называтся моделями представления

    Вспомогательные модели для промежуточных вычислений

Как правило, для хранения моделей создается в проекте отдельная папка Models . Модели представления нередко помещаются в отдельную папку, которая нередко называется ViewModels .

Проект ASP.NET MVC Core со встроенной аутентификацией по умолчанию уже содержит эти папки, и в них находятся в все необходимые модели. Однако если мы создаем проект без встроенной аутентификации, то эти папки отсутствуют. И соответственно нам надо добавить эти папки вручную. Но опять же подчеркну, что нам необязательно называть папки для хранения моделей именно Models и ViewModels. Это могут быть каталоги с любыми называниями, можно помещать модели в корень проекта, но более распространенным стилем являются названия Models и ViewModels.

Например, создадим новый проект ASP.NET Core по типу Web Application и назовем его ModelsApp . Вначале добавим в проект папку Models для хранения моделей.

И в нее поместим новый класс Company:

Public class Company { public int Id { get; set; } public string Name { get; set; } public string Country { get; set; } }

И также добавим в папку Models класс Phone

Public class Phone { public int Id { get; set; } public string Name { get; set; } public Company Manufacturer { get; set; } public decimal Price { get; set; } }

Эти модели будут описывать данные, которые мы будем использовать. Эти данные могут храниться в базе данных, но для простоты мы определим их в контроллере. Изменим контроллер HomeController следующим образом:

Using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; using ModelsApp.Models; // пространство имен моделей namespace ModelsApp.Controllers { public class HomeController: Controller { List companies; ListPhones; public HomeController() { Company apple = new Company { Id = 1, Name = "Apple", Country="США" }; Company microsoft = new Company { Id = 2, Name = "Microsoft", Country="США" }; Company google = new Company { Id = 3, Name = "Google", Country="США" }; companies = new List { apple, microsoft, google }; phones = new List { new Phone { Id=1, Manufacturer= apple, Name="iPhone 6S", Price=56000 }, new Phone { Id=2, Manufacturer= apple, Name="iPhone 5S", Price=41000 }, new Phone { Id=3, Manufacturer= microsoft, Name="Lumia 550", Price=9000 }, new Phone { Id=4, Manufacturer= microsoft, Name="Lumia 950", Price=40000 }, new Phone { Id=5, Manufacturer= google, Name="Nexus 5X", Price=30000 }, new Phone { Id=6, Manufacturer= google, Name="Nexus 6P", Price=50000 } }; } public IActionResult Index() { return View(phones); } } }

Список объектом модели передается в представление с помощью метода View() .

И в конце изменим представление Index.cshtml , которое будет выводить все объекты:

@using ModelsApp.Models @model IEnumerable @{ ViewData["Title"] = "Home Page"; } @foreach (Phone p in Model) { }
@p.Name@p.Manufacturer?.Name@p.Price

Вверх