Вопрос об иерархии и шаблонах проектирования - PullRequest
5 голосов
/ 30 апреля 2011

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

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

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

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

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

Было бы хорошо, если бы вы могли дать мне несколько советов о том, как смоделировать класс документа, или если бы вы могли рассказать мне о некоторых шаблонах проектирования, которые я должен использовать.

Заранее спасибо.


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

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

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

Ответы [ 5 ]

1 голос
/ 30 апреля 2011

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

Если тип находится в документе, есть отправитель.

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

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

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

РЕДАКТИРОВАТЬ:

Что касается вашего комментария: возможно, есть.Я не знаю, какой язык вы планируете использовать.Но, например, в Java каждый объект (person, company ..) может быть классом, реализующим интерфейс (например, вызов интерфейса Entity).Затем с помощью обобщений вы можете создать экземпляр своего класса, сделав обобщенный тип реализацией интерфейса.Что-то вроде:

public interface Entity{...}
public class Document<T implements Entity>{}
1 голос
/ 30 апреля 2011

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

ISender может быть реализован Person и Company.IReceiver может быть реализован Person, Company и Department.

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

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

0 голосов
/ 30 апреля 2011

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

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

Если, с другой стороны, все ваши документы перепутаны, и вы в основном обрабатываете их во время выполнения, тогда другое решение (которое я скоро расскажу) может быть чище.Я подозреваю, что это почти наверняка верно в отношении типов отправителя и получателя, которые почти наверняка не требуют иерархии (хотя, в зависимости от вашего языка, вам может понадобиться использовать интерфейс marker , чтобыподражать функциональному решению, которое я собираюсь представить).В этих случаях вам нужно что-то вроде «enum with data».В объектно-функциональном языке, таком как F #, вы можете комбинировать типы записей и дискриминантные объединения для моделирования этой скважины:

type PersonInfo = {Name:string ; Age:int}

type CompanyInfo = {Name:string ; Location:string} 

type sender =
    | Person of PersonInfo
    | Company of CompanyInfo

type DepartmentInfo = {Name:string ; Floor: int}

type receiver =
    | Person of PersonInfo
    | Company of CompanyInfo
    | Department of DepartmentInfo

type documentType =
    | In of sender
    | Out of receiver

type Document = {Type:documentType ; Title:string ; Body:string ; Date:DateTime } with 
    //example of how to process a Document using pattern matching
    override this.ToString() =
        match this.Type with
        | In(s) -> 
            match s with
            | sender.Person(info) -> sprintf "In / Person, extra info: Name = %s ; Age= %i" info.Name info.Age
            | sender.Company(_) -> "In / Company"
        | Out(r) ->
            match r with
            | receiver.Person(_) -> "In / Person"
            | receiver.Company(_) -> "In / Company"
            | receiver.Department(_) -> "In / Department"


//create a list of In and Out documents all mixed up
let documents = 
   [{Type = In(sender.Person({Name="John"; Age=3})); Title="My In Doc"; Body="Hello World"; Date=DateTime.Now}
    {Type = Out(receiver.Department({Name="John"; Floor=20})); Title="My Out Doc"; Body="Testing"; Date=DateTime.MinValue}]

//partition documents into a list of In and Out Types

let inDocuments, outDocuments = 
    documents |> List.partition (function | {Type=In(_)} -> true | {Type=Out(_)} -> false)
0 голосов
/ 30 апреля 2011

В основном это сводится к этому. Если будет, если такие заявления, как

if(document.IsIncoming()){
  do something
}elseif (document.SentToDepartment()) {
  do something else
}

повторяется более чем в нескольких местах, в которых вам лучше бы использовать какое-то полиморфное решение (например, абстрактный класс или интерфейс). То же самое с типами отправителя и получателя.

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

public class Document
{
  DocumentType type;
  IPrinter printer;
}
interface IPrinter{
  print();
}

class IncomingPrinter :IPrinter{}

class OutgoingPrinter :IPrinter{}

Всякий раз, когда решается, что документ будет входить (возможно, при его создании), вы назначаете IncomingPrinter. Если есть несколько типов поведения, которые должны быть назначены, как это обычно используется фабричный образец. Таким образом вы локализуете операторы if (doc.IsIncoming ()) в одном месте. Преимуществ не повторять решение в разных местах кода много.

0 голосов
/ 30 апреля 2011

Я здесь против иерархий.Отправитель и получатель - это понятия, которые имеют определенное поведение и содержат некоторые данные.Я бы сосредоточился на этих обязанностях и создал бы сущностей Sender и Reciever.Позже, если необходимо, создайте подклассы таких как CompanySender.По сути, не создавайте сущность Компании с логикой отправителя, если вся ваша система не связана с отправителями и получателями (я полагаю, что это не так).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...