v.ki 发表于 2021-11-6 19:48:39

优雅的编程————面向对象还能这么玩

原文链接在这里:优雅的编程————面向对象还能这么玩

刚开始学面向对象的时候其实,我是完全不懂的。

我不懂它为什么要那么弄,我不懂它有何作用,我不懂它存在的意义


前段时间,我把一些代码重构了一遍,由于之前写的过于臃肿,看起来就像这样,由于我当初追求的是能运行就行,之前也没去管它,直到有一天我受不了了。。。



功能很简单,就是实现登录的功能。但是用了一堆if else。可读性烂的像一坨图片

直到我想起了面向对象,一切都变了





长度可能和之前差不多,但是变得优雅了,可读性更强了

我目前认为用面向对象有两个好处(鬼知道随着时间推移会有啥更深入的想法呢)

1.就是大家经常提到的,提高代码的可读性
2.人们提到的不多,但是很重要就是对开发者更加友好。

第二点,之所以提到的不多,是因为我们通常都是用别人或者是编程语言自带的方法,功能,也不需要知道是怎么实现的。

01

假设有一天我开发了一个web框架供其他开发者使用,web框架非常良心给使用者一个查看查看用户信息的自带功能,这样开发者就不用自己写了。

当然以下只是演示,真正的web框架源码比这复杂多了。

框架提供的查看用户信息源码可以这么写:myframework/userinfo.py
class Check_info:
    def __init__(self,username):
      self.username=username
      self.password =123 #去数据库里查username对应的密码
      self.name=['vk']


开发者使用框架时只需要:

from myframework.userinfo import Check_info
username=input('这里是开发者让用户输入用户名')
pwd=Check_info(username)
print(pwd.password)

但是这样用户可以查看其他用户的密码了这时候我们需要加入限制,把密码属性隐藏起来

加入权限限制 :__开头的属性是私有属性,不允许直接访问,开发者只能调pwd访问


class Check_info:
    def __init__(self,username):
      self.__password =123#我是私有属性
      self.username=username
      self.name=['vk']
    def pwd(self):
      message='非法闯入'
      if self.username in self.name:
            message=self.__password
            return message
      else:
            return message

开发者使用框架时只需要:   
user=Check_info('1')
print(user.pwd()) #注意看这里

问题又来了,看第二行,开发者明明想获得属性的值。

正常应该是xxx.xxx获取,但是web框架给的通过xxx.xx()函数式调用,不太符合常理,和开发者的使用习惯

这时候我们可以使用property

class Check_info:
    def __init__(self,username):
      self.__password =123#我是私有属性
      self.username=username
      self.name=['vk']
    @property #加上这个装饰器我们就可以用获取属性的方法获取了
    def pwd(self):
      message='非法闯入'
      if self.username in self.name:
            message=self.__password
            return message
      else:
            return message

#开发者这么调      
pwd=Check_info('vk')
print(pwd.pwd)


这样web框架就可以实现既检查了用户的访问权限,又给开发者一个符合习惯的接口
02

python中我们可以通过len()函数来获得给定变量的长度,无论给len的参数是字符串,列表,集合,元组,字典。都可以。想象一下可以怎么实现呢?

我们要是我们自己写一个类似与len()函数的功能,应该如何实现呢

python中有个内置方法叫做__len__()就相当于不管是什么对象,它被创建就自带一个__len__()的方法。假设我们是python语言的设计者源码可以这么写


class variable:
    """
    我是一切变量规定我的子类有__len__()方法
    """
   
class list(variable):
    def __len__():
      """
      计算长度的算法
       """
class tuple(variable):
    def __len__():
      """
      计算长度的算法
      """
class dict(variable):
    def __len__():
      """
      计算长度的算法
      """

我只要是个变量,我们就继承那个variable()类

了解了python可能是如何设置内置方法的后(当然这只是可能,我也没去看python的 源码),我们自己实现它自带的len()方法就好办了。

只需这样:


def myownlen(obj):
    return obj.__len__()
myownlen('我是字符串')
myownlen()

由于所有的obj都带有__len__()的方法,我们无需考虑它是什么类型。

但是其实可以更加简化,我们没必要都继承一个父类,只需要在写代码的时候约定,看起来差不多的东西,都有某个方法。

比如上面的,我们不管它到底是什么类型,只需要它看起来可以计算长度就给他__len__()方法。

可以这么优化,直接去掉父类,继承:

class list():
    def __len__():
      """
      计算长度的算法
       """
class tuple():
    def __len__():
      """
      计算长度的算法
      """
class dict():
    def __len__():
      """
      计算长度的算法
      """

从规范的角度来书写代码,使他们都有同一个功能,看起来继承了相同的父类。


“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”


这就是鸭子类型。

在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。


页: [1]
查看完整版本: 优雅的编程————面向对象还能这么玩