美文网首页
架构师训练营第3周作业 设计模式

架构师训练营第3周作业 设计模式

作者: 浩哥有料 | 来源:发表于2020-06-24 23:47 被阅读0次

请在草稿纸上手写一个单例模式的实现代码,拍照提交作业。

我平时使用的编程语言是python,因此本作业使用python代码完成。不同的编程语言在实现单例模式的时候可以利用各自语言的不同特性,这里给出了三种基于python特性的单例模式实现方法。

第一种方法是借助类变量以及__new__()函数。在Python中,类变量是被类的所有实例所共享的,而实例变量只属于某个特定的实例。Python的类在实例化的时候会自动调用一个名为__new__的函数,这个函数的用来创建类的实例,而__init__函数则用来对实例进行初始化,因此__new__函数的调用是在__init__函数之前,它们两者的参数列表是一样的,只不过__new__的第一个参数我们习惯性写成cls,它代表的是当前的类,而__init__函数的第一个参数我们习惯性写成self,它代表的是当前的实例。因此,在__new__函数中我们可以使用cls.这样的形式来操作类变量,而在__init__函数里我们可以使用self.这样的形式来操作实例变量。

在这段程序中,我们在Singleton类中定义了一个类变量__instance,用来存储这个类的实例,它的初始值为None。 然后重写__new__函数,使其先判断一下类变量__instance是否有值,如果有就直接返回这个值,这个值就是该类的单一实例,如果没有值的话,就调用Singleton类的父类的__new__函数,实现Singleton类的实例化,并将这一实例存储到类变量__instance并返回。这样一来,每次对Singleton类进行实例化的时候都会先识别一下__instance是否有值,如果有值就不再创建新的实例,从而确保了Singleton类的单例特性。

如果Singleton类需要有实例属性,那么我们还需要写上__init__函数。虽然__new__函数能够确保返回的是唯一的实例,但是__init__函数如果不做限制,仍会在每次调用的时候修改这个实例的实例变量。因此我们再创建一个类变量__is_first,用于指定是否是首次对类的实例进行初始化,并将其初始值设为False。然后在__init__函数中对这个类变量进行判断(注意,由于类变量会被所有实例共享,因此这里的self.__is_first就相当于cls.__is_first),只有当它为False是才会执行实例的初始化,即对实例变量赋值,赋值完后将__is_first改为True。这样一来,当我们后面再对Singleton类进行实例化的时候,即便传入的新的参数,__init__函数也不会再使用这些新的参数值来修改实例,从而确保Singleton类的实例永远是最初创建的单一实例。

第三种方法是借助Python强大的装饰器特性。由于Python中一切皆对象,包括类、实例、函数本身也是一个对象,并且函数可以返回任意类型的对象,因此我们可以通过函数对类进行包装,为类添加附加的功能。

这里我们编写一个装饰器函数singleton_decorator,其第一个参数是cls,代表它会接受一个类并对这个类进行包装,后面的不定长参数*arg**kwargs则用于支持任意的实例化参数列表。这个函数中有一个字典instance,它用来存储被这个函数所装饰的各个类的单例。装饰器内部的处理函数wrap会先判断被装饰的类是否在该字典中,如果不在就对类进行实例化并存入字典,然后返回这个实例,如果已经在字典中,就直接返回字典中存储的实例。

接下来,我们只需在Singleton类的头部使用@singleton_decorator,就可以直接将Singleton类装饰成一个支持单例模式的类。

请用组合设计模式编写程序,打印输出图 1 的窗口,窗口组件的树结构如图 2 所示,打印输出示例参考图 3。

注:作业说明中“记住用户名”用的是TextBox,正确的应该是Label。


这个作业让我想起了工作中常用的Qt框架,Qt是非常常用的跨平台UI框架,它创建UI的过程就是非常典型的组合模式的体现:各种控件包括容器都是继承自QWidget,QWidget本身也是一个容器,可以在其中添加QLayout、QForm等等,每个容器中又可以添加各类控件。因此以下代码仿照了Qt框架创建UI的过程。

# coding: utf-8

class Widget(object):
    """Components base class."""

    def __init__(self, name):
        self._name = name

    def show(self):
        """Show the class name and the instance name."""
        print '{}({})'.format(self.__class__.__name__,
                              self._name)


class Layout(Widget):
    """Composite base class. It's also a Widget instance.
    
    We can add other components into this composite or
    remove any component from this composite.

    """

    def __init__(self, name):
        super(Layout, self).__init__(name)
        self._widgets = []

    def add_widget(self, widget):
        self._widgets.append(widget)

    def remove_widget(self, widget):
        self._widgets.remove(widget)

    def show(self):
        super(Layout, self).show()
        for widget in self._widgets:
            widget.show()


class WinForm(Layout):
    pass


class Picture(Widget):
    pass


class Button(Widget):
    pass


class Frame(Layout):
    pass


class Label(Widget):
    pass


class TextBox(Widget):
    pass


class PasswordBox(Widget):
    pass


class CheckBox(Widget):
    pass


class LinkLabel(Widget):
    pass


def make_window():
    """Test functionality."""

    # Initialize all components and composites.
    form = WinForm('WINDOW窗口')
    pic = Picture('LOGO图片')
    login_button = Button('登录')
    register_button = Button('注册')
    frame = Frame('FRAME1')
    name_label = Label('用户名')
    name_input = TextBox('文本框')
    passwd_label = Label('密码')
    passwd_input = PasswordBox('密码框')
    remember_check = CheckBox('复选框')
    remember_label = Label('记住用户名')
    forget_link = LinkLabel('忘记密码')

    # Add components into composite.
    frame.add_widget(name_label)
    frame.add_widget(name_input)
    frame.add_widget(passwd_label)
    frame.add_widget(passwd_input)
    frame.add_widget(remember_check)
    frame.add_widget(remember_label)
    frame.add_widget(forget_link)

    # Add components and composite into another composite.
    form.add_widget(pic)
    form.add_widget(login_button)
    form.add_widget(register_button)
    form.add_widget(frame)

    # Show the top composite.
    form.show()

make_window()

运行结果:

WinForm(WINDOW窗口)
Picture(LOGO图片)
Button(登录)
Button(注册)
Frame(FRAME1)
Label(用户名)
TextBox(文本框)
Label(密码)
PasswordBox(密码框)
CheckBox(复选框)
Label(记住用户名)
LinkLabel(忘记密码)

相关文章

网友评论

      本文标题:架构师训练营第3周作业 设计模式

      本文链接:https://www.haomeiwen.com/subject/nbljfktx.html