Устранение множественного наследования - PullRequest
9 голосов
/ 15 июля 2009

У меня следующая проблема, и мне интересно, есть ли хороший способ для моделирования этих объектов без использования множественного наследования. Если это имеет какое-то значение, я использую Python.

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

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

Кроме того, все эти объекты должны иметь общий базовый класс.

Ответы [ 8 ]

8 голосов
/ 15 июля 2009

То, что у вас есть, является примером Role - это обычная ловушка для моделирования Role с помощью наследования, но роли могут изменяться, и изменение структуры наследования объекта (даже в языках, где это возможно, например, Python), не рекомендуется. Дети растут и становятся взрослыми, и некоторые взрослые также будут родителями детей-учеников, а также самими взрослыми учениками - они могут затем отказаться от любой роли, но должны сохранить другую (их ребенок меняет школу, но не меняет или наоборот) .

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

5 голосов
/ 15 июля 2009

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

Мне также приходит в голову, что Python поддерживает утку, набирающую , в связи с чем возникает вопрос "Почему так важно, чтобы все классы имели общий базовый класс?"

2 голосов
/ 15 июля 2009

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

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

2 голосов
/ 15 июля 2009

Очень простое решение: используйте композицию, а не наследование. Вместо того, чтобы Student наследовал от Contact и Billing, сделайте Contact полем / атрибутом Person и наследуйте от него. Сделайте выставление счетов студенту. Сделайте Родителя полем для себя.

1 голос
/ 15 июля 2009

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

классы: Персона, BillingInfo, StudentInfo.

Все люди являются экземплярами класса Person ...

class Person:
    # Will have contact fields all people have - or you could split these off into an
    # object.
    parent        # Will be set to None for adults or else point to their parent's
                  # Person object.
    billing_info  # Set to None for non-adults, else to their BillingInfo object.
    student_info  # Set to None for non-student parents, else to their StudentInfo
                  # object. 

Проверка полей позволит вам создавать списки по вашему желанию.

1 голос
/ 15 июля 2009

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

В этом случае я, вероятно, в конечном итоге сделаю что-нибудь, когда вы загрузите данные, чтобы также установить для них интерфейсы маркеров в зависимости от некоторой информации, например, если age> = 18, вы устанавливаете интерфейс IAdult и т. Д. Затем вы можете получить информация для взрослых, выполнив

adultschema = IAdultSchema(person)

или что-то в этом роде. (Изменить: На самом деле я бы, вероятно, использовал

queryAdapters(person, ISchema)

чтобы получить все схемы за один раз. :)

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

Посмотрите, как Брэндонс отлично говорит о PyCon: http://www.youtube.com/watch?v=UF77e2TeeQo И мое вступительное сообщение в блоге: http://regebro.wordpress.com/2007/11/16/a-python-component-architecture/

0 голосов
/ 15 июля 2009

В псевдокоде вы можете сделать что-то вроде этого:

Class Student
    Inherits WhateverBase

    Private m_StudentType as EnumStudentTypes 'an enum containing: Adult, Child
    Private m_Billing as Billing
    Private m_Contact as Contact
    Private m_Parent as Parent

    Public Sub Constructor(studentType, billing, contact, parent)
        ...logic to make sure we have the right combination depending on studentType.
        ...throw an exception if we try to assign a a parent to an adult, etc.
        ...maybe you could have seperate constructors, one for each studenttype.             
    End Sub


    Public Property StudentType as EnumStudentTypes
        Get
             Return m_StudentType
        End Get
    End Sub

    Public Property Parent 
        Get 
           ...code to make sure we're using a studentType that has a parent,
           ...and throws an exception if not. Otherwise it returns m_Parent
        End Get
    End Sub


    [more properties]
End Class Student

Тогда вы можете создать класс с именем StudentManager:

Public Class StudentManager
    Public Function GetAdults(studentCollection(Of Students)) as StudentCollection(Of Students)
        Dim ResultCollection(Of Students)

        ...Loop through studentCollection, adding all students where Student.StudentType=Adult  

        Return ResultCollection
    End Function


    [Other Functions]
End Class

Public Enum StudentType
    Adult=0
    Child=1  
End Enum
0 голосов
/ 15 июля 2009

Одним из решений является создание базового класса / интерфейса Info, от которого наследуются классы ContactInfo, StudentInfo и BillingInfo. Имейте некоторый объект Person, который содержит список объектов Info, и затем вы можете заполнить список объектов Info с помощью ContactInfo, StudentInfo и т. Д.

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