设计模式将两个实现合并为一个类

时间:2017-09-24 23:51:38

标签: python inheritance design-patterns python-2.x

我无法找出建模此问题的正确方法。 在这里,我给你一个我的代码的简约版本:

# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod

class AreaCalculator():
    __metaclass__ = ABCMeta

    def __init__(self):
        pass

    @abstractmethod
    def getArea(self):
        pass

    def compute(self):
        self.getArea()


class PerimeterCalculator():
    __metaclass__ = ABCMeta

    def __init__(self):
        pass

    @abstractmethod
    def getPerimeter(self):
        pass

    def compute(self):
        self.getPerimeter()


class TriangleAreaCalculator(AreaCalculator):

    def __init__(self):
        AreaCalculator.__init__(self)

    def getArea(self):
        return area

class TrianglePerimeterCalculator(PerimeterCalculator):

    def __init__(self):
        PerimeterCalculator.__init__(self)

    def getPerimeter(self):
        return perimeter



a = TriangleAreaCalculator()
b = TrianglePerimeterCalculator()

是否有一种优雅的方式来合并" TrianglePerimeterCalculator"和" TriangleAreaCalculator"课程分为一部分,但保持" PerimeterCalculator"和" AreaCalculator"分离

[编辑]正如Kyle在评论中所建议的那样,我可以创建一个新的类(让我们称之为" Triangle")继承自" PerimeterCalculator"和" AreaCalculator"同时,但我想要的是能够告诉一个新的" Triangle"表现为" PerimeterCalculator"或" AreaCalculator",但不能同时进行。

3 个答案:

答案 0 :(得分:2)

我认为"设计模式"你应该使用的是多重继承。下面是您的代码的修改版本,演示了它是如何做的(加上一些其他更改使其实际可运行,所有类都是新风格)。

from abc import ABCMeta, abstractmethod

class AreaCalculator(object):
    __metaclass__ = ABCMeta

    def __init__(self):
        pass

    @abstractmethod
    def getArea(self):
        pass

    def compute(self):
        self.getArea()


class PerimeterCalculator(object):
    __metaclass__ = ABCMeta

    def __init__(self):
        pass

    @abstractmethod
    def getPerimeter(self):
        pass

    def compute(self):
        self.getPerimeter()


class TriangleAreaCalculator(AreaCalculator):

    def __init__(self):
        super(TriangleAreaCalculator, self).__init__()

    def getArea(self):
        print('TriangleAreaCalculator.getArea() called on instance of {}'.format(
            self.__class__.__name__))
#        return area
        return 13

class TrianglePerimeterCalculator(PerimeterCalculator):

    def __init__(self):
        super(TrianglePerimeterCalculator, self).__init__()

    def getPerimeter(self):
        print('TrianglePerimeterCalculator.getPerimeter() called on instance of {}'.format(
            self.__class__.__name__))
#        return perimeter
        return 42


class MergedCalculator(TriangleAreaCalculator, TrianglePerimeterCalculator):

    def __init__(self):
        super(MergedCalculator, self).__init__()

merged = MergedCalculator()
print('merged.getArea() -> {}'.format(merged.getArea()))
print('merged.getPerimeter() -> {}'.format(merged.getPerimeter()))

输出:

TriangleAreaCalculator.getArea() called on instance of MergedCalculator
merged.getArea() -> 13
TrianglePerimeterCalculator.getPerimeter() called on instance of MergedCalculator
merged.getPerimeter() -> 42

答案 1 :(得分:1)

在编辑和澄清您的问题之后,这是另一个答案。它允许根据需要创建单个 Triangle实例,其行为可以像AreaCalculatorPerimeterCalculator

这种编程模式称为"委托"并且用于将实现特定操作的责任移交给另一个对象的地方 - 在这种情况下是一个其他类的内部持有的实例。在Python中执行此操作的常用方法是覆盖类的默认__getattr__()方法。

由于您从未在我的其他答案中回复有关控制使用哪种行为的确切内容的评论,因此我添加了set_behavior()方法以允许明确指定。

from abc import ABCMeta, abstractmethod


class AreaCalculator:
    __metaclass__ = ABCMeta

    def __init__(self):
        pass

    @abstractmethod
    def getArea(self):
        pass

    def compute(self):
        return self.getArea()


class PerimeterCalculator:
    __metaclass__ = ABCMeta

    def __init__(self):
        pass

    @abstractmethod
    def getPerimeter(self):
        pass

    def compute(self):
        return self.getPerimeter()


class TriangleAreaCalculator(AreaCalculator):

    def __init__(self):
        super(TriangleAreaCalculator, self).__init__()

    def getArea(self):
        print('TriangleAreaCalculator.getArea() called')
        area = 13
        return area



class TrianglePerimeterCalculator(PerimeterCalculator):

    def __init__(self):
        super(TrianglePerimeterCalculator, self).__init__()

    def getPerimeter(self):
        print('TrianglePerimeterCalculator.getPerimeter() called')
        perimeter = 42
        return perimeter


class Triangle:

    def __init__(self):
        delegate_classes = TriangleAreaCalculator, TrianglePerimeterCalculator

        # Map delegate classes to instances of themselves.
        self._delegates = {delegate_class: delegate_class()
                            for delegate_class in delegate_classes}

        self.set_behavior(TriangleAreaCalculator)  # Set default delegate.

    def __getattr__(self, attrname):
        # Called only for attributes not defined by this class (or its bases).
        # Retrieve attribute from current behavior delegate class instance.
        return getattr(self._behavior, attrname)

    def set_behavior(self, delegate_class):
        try:
            self._behavior = self._delegates[delegate_class]
        except KeyError:
            raise TypeError("{} isn't a valid {} behavior delegate class"
                              .format(delegate_class, self.__class__.__name__))


if __name__ == '__main__':

    triangle = Triangle()
    # Uses instance's default behavior.
    print('triangle.compute() -> {}'.format(triangle.compute()))

    triangle.set_behavior(TrianglePerimeterCalculator)  # Change behavior.
    print('triangle.compute() -> {}'.format(triangle.compute()))

输出:

TriangleAreaCalculator.getArea() called
triangle.compute() -> 13
TrianglePerimeterCalculator.getPerimeter() called
triangle.compute() -> 42

答案 2 :(得分:0)

我自己想出来,灵感来自Kyle和martineau的评论/答案。

我可以创建一个合并的类“Triangle”,如下所示:

   private void create_ans_btns(string newWord)
    {            
        LinearLayout ll = (LinearLayout)FindViewById(Resource.Id.linearLayout);
        Button[] ans_btn = new Button[newWord.Length];

        for (int counter = 0; counter < newWord.Length; counter++)
        {
            ans_btn[counter] = new Button(this);
            ans_btn[counter].Id = counter;
            ans_btn[counter].Text = "" + counter;
            ans_btn[counter].SetHeight(50);
            ans_btn[counter].SetWidth(50);
            ll.AddView(ans_btn[counter]);

            /*
            ans_btn[counter].Click += delegate { ans_btn[counter].Text = ""; };
            */
        }            
    }

然后按如下方式修改TriangleAreaCalculator和TrianglePerimeterCalculator:

class Triangle():

    def __init__(self):
        pass

    def getTriangleArea(self):
        print 'Triangle area'

    def getTrianglePerimeter(self):
        print 'Triangle perimeter'

这样,我可以创建一个新的类似Triangle的实例,其行为为“PerimeterCalculator”或“AreaCalculator”(但不是同时):

class TriangleAreaCalculator(AreaCalculator, Triangle):

    def __init__(self):
        TriangleCalculator.__init__(self)
        AreaCalculator.__init__(self)

    def getArea(self):
        super(TriangleAreaCalculator, self).getTriangleArea()

class TrianglePerimeterCalculator(PerimeterCalculator, Triangle):

    def __init__(self):
        TriangleCalculator.__init__(self)
        PerimeterCalculator.__init__(self)

    def getPerimeter(self):
        super(TrianglePerimeterCalculator, self).getTrianglePerimeter()
相关问题