消除多重继承

发布于 2024-07-26 20:46:39 字数 298 浏览 1 评论 0 原文

我遇到以下问题,我想知道是否有一种好的方法可以在不使用多重继承的情况下对这些对象进行建模。 如果有什么区别的话,我正在使用Python。

学生需要联系信息以及学生信息。 成年人需要联系信息和账单信息。 学生可以是成年学生,在这种情况下我需要联系/学生/账单信息,或者他们可以是儿童,在这种情况下我需要联系/学生/家长信息。

只是为了清楚如何使用该系统,我需要能够请求所有成人的列表(我将获得成人学生加上家长),或所有学生的列表(我将获得儿童学生加上家长)成人学生)。

此外,所有这些对象都需要有一个共同的基类。

I have the following problem and I'm wondering if there's a nice way to model these objects without using multiple inheritance. If it makes any difference, I am using Python.

Students need contact information plus student information. Adults need contact information plus billing information. Students can be adult students, in which case I need contact/student/billing info, or they can be children, in which case I need contact/student/parent info.

Just to be clear on how the system will be used, I need to be able to ask for a list of all adults (and I will get adult students plus parents), or a list of all students (and I will get child students plus adult students).

Also, all of these objects need to have a common base class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

梦里人 2024-08-02 20:46:39

您所拥有的是角色的示例——通过继承对角色进行建模是一个常见的陷阱,但是角色可以更改,并且不建议更改对象的继承结构(即使在可能的语言中,例如Python)。 孩子们长大成人,一些成年人也将成为儿童学生的父母以及成年学生自己——他们可能会放弃其中一个角色,但需要保留另一个角色(他们的孩子转学,但他们没有转学,反之亦然) 。

只需有一个包含必填字段和可选字段的 Person 类,后者代表角色,可以更改。 “请求列表”(与继承或其他方式完全无关)可以通过动态构建列表(遍历所有对象以检查每个对象是否满足要求)或维护与可能的要求相对应的列表(或频繁查询和临时查询的两种策略的混合)。 某种数据库可能会在这里有所帮助(并且大多数数据库在没有继承的情况下工作得更好;-)。

What you have is an example of Role -- it's a common trap to model Role by inheritance, but Roles can change, and changing an object's inheritance structure (even in languages where it's possible, like Python) is not recommended. Children grow and become adults, and some adults will also be parents of children students as well as adult students themselves -- they might then drop either role but need to keep the other (their child changes schools but they don't, or viceversa).

Just have a class Person with mandatory fields and optional ones, and the latter, representing Roles, can change. "Asking for a list" (quite independently of inheritance or otherwise) can be done either by building the list on the fly (walking through all objects to check for each whether it meets requirements) or maintaining lists corresponding to the possible requirements (or a mix of the two strategies for both frequent and ad-hoc queries). A database of some sort is likely to help here (and most DBs work much better without inheritance in the way;-).

病女 2024-08-02 20:46:39

我确信其他人很快就会发表评论(如果他们还没有),一个好的面向对象原则是“优先考虑组合而不是继承”。 从您的描述来看,您似乎违反了单一责任原则,并且应该将功能分解为单独的对象。

我还想到Python支持鸭子打字,这就引出了一个问题“为什么会这样”所有类都有一个共同的基类很重要吗?”

As I'm sure someone else will comment soon (if they haven't already), one good OO principle is "Favor composition over inheritance". From your description, it sounds suspiciously like you're breaking the Single Responsibility Principle, and should be breaking down the functionality into separate objects.

It also occurs to me that Python supports duck typing, which begs the question "Why is it so important that all the classes have a common base class?"

故人如初 2024-08-02 20:46:39

非常简单的解决方案:使用组合而不是继承。 不要让 Student 从 Contact 和 Billing 继承,而是将 Contact 设为 Person 的字段/属性并从中继承。 让计费成为学生的一个领域。 使 Parent 成为 Person 的自引用字段。

Very simple solution: Use composition rather than inheritance. Rather than having Student inherit from Contact and Billing, make Contact a field/attribute of Person and inherit from that. Make Billing a field of Student. Make Parent a self-reference field of Person.

檐上三寸雪 2024-08-02 20:46:39

听起来你并不真的需要多重继承。 事实上,您并不真正需要多重继承。 这只是多重继承是否简化了事情的问题(我在这里不认为是这种情况)。

我将创建一个 Person 类,其中包含成人和学生共享的所有代码。 然后,您可以拥有一个 Adult 类,其中包含成人所需的所有内容,以及一个 Child 类,其中包含儿童所需的代码。

It doesn't sound like you really need multiple inheritance. In fact, you don't ever really need multiple inheritance. It's just a question of whether multiple inheritance simplifies things (which I couldn't see as being the case here).

I would create a Person class that has all the code that the adult and student would share. Then, you can have an Adult class that has all of the things that only the adult needs and a Child class that has the code only the child needs.

苏别ゝ 2024-08-02 20:46:39

这听起来像是可以通过组件架构(例如 zope.components)非常漂亮且灵活地完成的事情。 组件在某种程度上是一种超级灵活的组合模式。

在这种情况下,当您加载数据以根据某些信息在其上设置标记接口时,我可能最终会做一些事情,例如如果年龄> = 18,则设置 IAdult 接口等。然后您可以获取成人信息通过做

adultschema = IAdultSchema(person)

或类似的事情。
(编辑:实际上我可能会用来

queryAdapters(person, ISchema)

一次性获取所有模式。:)

组件架构可能有点过头了,但是一旦你习惯了这样的思考,许多问题就会变得微不足道。 :)

查看 Brandons 出色的 PyCon 讨论:http://www.youtube.com/watch ?v=UF77e2TeeQo
我的介绍性博客文章: http://regebro.wordpress .com/2007/11/16/a-python-component-architecture/

This sounds like something that could be done quite nicely and flexibly with a component architecture, like zope.components. Components are in a way a sort of super-flexible composition patterns.

In this case I'd probably end up doing something when you load the data to also set marker interfaces on it depending on some information, like if age >= 18 you set the IAdult interface, etc. You can then get the adult information by doing

adultschema = IAdultSchema(person)

or something like that.
(Edit: Actually I'd probably use

queryAdapters(person, ISchema)

to get all schemas in one go. :)

A component architecture may be overkill, but once you got used to thinking like that, many problems get trivial. :)

Check out Brandons excellent PyCon talk about it: http://www.youtube.com/watch?v=UF77e2TeeQo
And my intro blog post: http://regebro.wordpress.com/2007/11/16/a-python-component-architecture/

陌上青苔 2024-08-02 20:46:39

我认为您的要求过于简单化,因为在实际情况下,您可能会让学生拥有自己的帐户来处理账单,即使他们是需要家长联系信息的未成年人。 此外,您的家长联系信息可能与实际情况中的账单信息不同。 您可能还需要与其他人一起结帐的成年学生。 但是,除此之外 - 根据您的要求,这里有一种方法:

类:Person、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. 

检查字段将允许您根据需要创建列表。

I think your requirements are over-simplified, since in a real situation, you might have students with their own accounts to handle billing even if they are minors who need parent contact information. Also, you might have parental contact information be different from billing information in an actual situation. You might also have adult students with someone else to bill. BUT, that aside - looking at your requirements, here is one way:

classes: Person, BillingInfo, StudentInfo.

All people are instances of class 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. 

Checking the fields will allow you to create lists as you desire.

思慕 2024-08-02 20:46:39

一种解决方案是创建 ContactInfo、StudentInfo 和 BillingInfo 类继承自的 Info 基类/接口。 拥有某种包含 Info 对象列表的 Person 对象,然后您可以使用 ContactInfo、StudentInfo 等填充 Info 对象列表。

One solution is to create a base Info class/interface that the classes ContactInfo, StudentInfo, and BillingInfo inherit from. Have some sort of Person object that contains a list of Info objects, and then you can populate the list of Info objects with ContactInfo, StudentInfo, etc.

半世蒼涼 2024-08-02 20:46:39

在伪代码中,您可以执行以下操作:

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

In pseudocode, you could do something like this:

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

Then you could create a class called 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文