Плохой дизайн?Используйте коллекцию абстрактных классов для включения конкретных детей - PullRequest
0 голосов
/ 29 января 2019

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

Мне удалось создать базовый класс IEnumerable, который содержит два ILists из конкретных потомков.Хотя конкретные дочерние элементы имеют один и тот же тип, идея состояла в том, чтобы вызвать конкретные дочерние свойства на веб-странице, если мне нужно.Конечно, у меня есть ощущение, что этот дизайн не совсем подходит для моих целей.

Класс для абстрактного класса:

 public abstract class MasterTicket
    {
        public Guid id{ get; set; }
        public DateTime openTime{ get; set; }
        public DateTime closeTime{ get; set; }
        public bool active{ get; set; }
        public string summary{ get; set; }
        public string description{ get; set; }
        public DateTime updateTime{ get; set; }
        //TODO: Create foreign key relationship to user model
        public Guid userUpdateId{ get; set; }
        //TODO: Create foreign key relationship for tickets from other systems
        public Guid externalAppId{ get; set; }
        //TODO: Create foreign key relationship to user model
        public Guid userOpenId{ get; set; }
        public Guid userOwnerId{ get; set; }
        public int timesUpdated{ get; set; }
        public DateTime expectedCompletionTime{ get; set; }
        public DateTime actualCompletionTime{ get; set; }
        public List<MasterTicketItem> masterTicketItems{ get; set; }
        }

Класс для конкретного дочернего класса:

public class ApptTaskTicket : MasterTicket
    {
        public DateTime currentApptTime;
        public string patientName;
        //TODO: Create foreign relationship
        public Guid subjectPrsnlId;
        public string patientPhone;
        public string patientEmail;
        public string preferredContactMethod;
    }

Пример контроллера:

public class QueueController : Controller
    {
        private static readonly IList<MasterTicket> tickets;

        private static readonly IEnumerable<MasterTicket> combined;

        static QueueController()
        {
            tickets = new List<MasterTicket>
            {
                new ApptTaskTicket
                {
                    id = Guid.NewGuid(),
                    summary = "Foopy",
                    description = "Please set up Foop Dawg."
                },
                new ApptTaskTicket
                {
                    id = Guid.NewGuid(),
                    summary = "Milk man",
                    description = "Milkman here I come"
                },
                new ApptTaskTicket
                {
                    id = Guid.NewGuid(),
                    summary = "InMode Presentation",
                    description = "Upcoming presentation next month"
                },
            };

            CalendarQuickStart eventFetcher = new CalendarQuickStart();

            IList<MasterTicket> addAppts = eventFetcher.LoadAppointmentTasks();

            combined = tickets.Concat(addAppts);

            tickets.Concat(addAppts);
        }
        // GET: Queue
        public ActionResult Queue()
        {

            return View(combined);
        }
    }

Просмотр страницы, отображающей этот список, в таблице:

@model IEnumerable<AffirmativeServiceSystem.Models.MasterTicket>

@{
    ViewBag.Title = "Queue";
}

<h2>Queue</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        @*<th>
            @Html.DisplayNameFor(model => model.openTime)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.closeTime)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.active)
        </th>*@
        <th>
            @Html.DisplayNameFor(model => model.summary)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.description)
        </th>
        @*<th>
            @Html.DisplayNameFor(model => model.updateTime)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.userUpdateId)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.externalAppId)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.userOpenId)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.userOwnerId)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.timesUpdated)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.expectedCompletionTime)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.actualCompletionTime)
        </th>*@
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        @*<td>
            @Html.DisplayFor(modelItem => item.openTime)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.closeTime)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.active)
        </td>*@
        <td>
            @Html.DisplayFor(modelItem => item.summary)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.description)
        </td>
        @*<td>
            @Html.DisplayFor(modelItem => item.updateTime)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.userUpdateId)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.externalAppId)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.userOpenId)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.userOwnerId)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.timesUpdated)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.expectedCompletionTime)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.actualCompletionTime)
        </td>*@
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.id }) |
            @Html.ActionLink("Details", "Details", new { id=item.id }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.id })
        </td>
    </tr>
}

</table>

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

Я ожидал, что смогу вызывать как абстрактные, так и конкретные свойства дочернего конкретного класса, но на самом деле я просто вижу свойства базового класса MasterTicket, когда пытаюсь использовать Intellisense для записи вкод для получившейся страницы просмотра.Должен ли я использовать несколько моделей, когда, например, пытаюсь использовать разные дочерние конкретные классы, такие как разные типы билетов базового билета?Идея состоит в том, чтобы один конкретный класс служил для подтверждений встреч из календаря, а другой - для предметов, связанных с поддержкой.

Заранее оцените ваши мысли.

1 Ответ

0 голосов
/ 29 января 2019

Я не уверен, что полностью понимаю вашу проблему, но могу вам дать несколько советов.Это не совсем ответ, но было бы слишком беспорядочно публиковать его как комментарий.

Советы:

  • Не создавайте абстрактный класс без какого-либо абстрактного свойстваили функция.

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

  • Нетозначает создание родительского или абстрактного класса, когда у этого родителя есть только один дочерний элемент.

  • Реальное значение абстрактного класса заключается в реализации функциональности без спецификации.

См. Этот простой пример «Читателя»:

public abstract class Reader
{
  public int ReadByte()
  {
    byte[] value = new byte[1];
    int read = Read(value, 0, 1);
    if (read == 0)
    {
      return -1;
    }

    return value[0];
  }

  public abstract int Read(byte[] value, int offset, int count);
}

public class DiskReader : Reader
{
  // TODO: implement reading from disk
  public override int Read(byte[] value, int offset, int count) => throw new System.NotImplementedException();
}

public class PortReader : Reader
{
  // TODO: implement reading from serial port
  public override int Read(byte[] value, int offset, int count) => throw new System.NotImplementedException();
}

public class NetworkReader : Reader
{
  // TODO: implement reading from network connection
  public override int Read(byte[] value, int offset, int count) => throw new System.NotImplementedException();
}

Реальной реализации не существует, но вы должны понять суть.Когда вы не используете некоторые абстрактные функции из абстрактного класса, нет необходимости создавать абстрактный класс.См. Использование не реализованной функции в функции ReadByte.

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

И на ваш вопрос: «почему вы можете видеть дочерние свойства»

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

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

...