17

我想知道如何在 python 中用UML 术语实现组合和聚合。

如果我明白:

  1. 聚合:

class B:
    pass

class A(object):
    def __init__(self):
        self.B = B

  1. 作品:

在其他语言中,我看到它实现为指向 B 的指针。我猜这self.B是 python 中的指针。

class A(object):
    def __init__(self, B):
        self.B = B

这样对吗?

4

3 回答 3

35

组合和聚合是关联的特殊形式。而关联是两个类之间没有任何规则的关系。

作品

在组合中,其中一个类由其他类的一个或多个实例组成。换句话说,一个类是容器,另一个类是内容,如果你删除容器对象,那么它的所有内容对象也会被删除。

现在让我们看一个 Python 3.5 中的组合示例。类Employee是容器,类Salary是内容。

class Salary:
    def __init__(self,pay):
        self.pay=pay

    def get_total(self):
       return (self.pay*12)

class Employee:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus
        self.obj_salary=Salary(self.pay)

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)


obj_emp=Employee(100,10)
print (obj_emp.annual_salary())

聚合

聚合是组合的一种弱形式。如果你删除容器对象内容,对象可以在没有容器对象的情况下存活。

现在让我们看一个 Python 3.5 中的聚合示例。同样,类Employee是容器,类Salary是内容。

class Salary:
    def __init__(self,pay):
        self.pay=pay

    def get_total(self):
       return (self.pay*12)

class Employee:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus

    def annual_salary(self):
        return "Total: "  +  str(self.pay.get_total()+self.bonus)


obj_sal=Salary(100)
obj_emp=Employee(obj_sal,10)
print (obj_emp.annual_salary())
于 2016-06-19T18:43:22.120 回答
34

如果我理解正确,聚合与组合是关于对象对其成员的责任(例如,如果您删除一个实例,您是否也删除了它的成员?)。

主要是,这在很大程度上取决于实施。例如,要创建一个接收类 B(聚合)实例的类 A,您可以编写以下代码:

class B(object): pass

class A(object):
    def __init__(self, b):
        self.b = b

b = B()
a = A(b)

但需要注意的是,Python 没有任何内置功能可以阻止您传入其他内容,例如:

a = A("string") # still valid

如果您想在 A(组合)的构造函数中创建 B 的实例,您可以编写以下内容:

class A(object):
    def __init__(self):
        self.b = B()

或者,您可以将类注入构造函数,然后创建一个实例,如下所示:

class A(object):
    def __init__(self, B):
        self.b = B()

顺便说一句,至少在您的第一个示例和可能的第二个示例中,您将 B 设置为 B 的类定义,而不是它的实例:

class A(object):
    def __init__(self, B):
        self.B = B

>>> a = A()
>>> a.B # class definition
<class __main__.B at 0x028586C0>
>>> a.B() # which you can make instances of
<__main__.B instance at 0x02860990>

所以,你最终得到了一个指向 B 的类定义的 A 实例,我很确定这不是你想要的。虽然,这通常用其他语言很难做到,所以我理解这是否是混淆点之一。

于 2013-11-08T15:53:38.700 回答
4
# Aggregation is NOT exclusive
class BaseChapter:
    '''
    We can use this BaseChapter in any book, like in OpenBook.
    '''

    def __init__(self, name):
        self.name = name
        self.subject = None
        self.content = None
        return

class OpenBook:

    def __init__(self, isbn):
        self.isbn = isbn
        self.chapters = list()

    def add_chapter(self, obj):

        # This constrain dont have correlation with composition/aggregation
        if isinstance(obj, BaseChapter):
            self.chapters.append(obj)
        else:
            raise TypeError('ChapterError')

# .. but Composition is Exclusive
# Example:
class MyBook:

    class MyChapter:
        '''
        This MyChapter can be used only by MyBook
        '''
        def __init__(self, name, subject):
            self.name = name
            self.subject = subject
            self.title = None
            self.content = None
            self.techincal_refs = list()
            return

    def __init__(self, isbn):
        self.isbn = isbn
        self.chapters = list()

    def add_chapter(self, obj):
        # This constrain dont have correlation with composition/aggregation
        # what is important here is MyChapter can be used only by MyBook
        # a outside object cant create a instance of MyChapter
        if isinstance(obj, self.MyChapter):
            self.chapters.append(obj)
        else:
            raise TypeError('ChapterError')

..是的,我们可以做得更好

class MyBook:

    class MyChapter(BaseChapter):
        '''
        This MyChapter can be used only by MyBook,
        but now is based in BaseChapter.
        But you knhow, python dont create problems if you still want
        create a instance of MyChapter in other 'Books'.

        But when you see this code you will think, This class is exclusive
        to MyBook.
        '''
        def __init__(self, name):
            super().__init__(name)
            self.subject = None
            self.title = None
            self.content = None
            self.techincal_refs = list()
            return

    def __init__(self, nib):
        self.nib = nib
        self.chapters = list()

    def add_chapter(self, obj):
        # This constrain dont have correlation with composition/agregation
        # what is important here is MyChapter can be used only by MyBook
        if isinstance(obj, self.MyChapter):
            self.chapters.append(obj)
        else:
            raise TypeError('ChapterError')
于 2016-09-27T12:40:37.333 回答