代码重用性/组合/继承/接口/抽象类

参考:https://www.cnblogs.com/zihe/p/7111092.html
“””
@staticmethod将类变成
@abstractmethod 修饰抽象类,只写类别,不写具体实现,具体实现由继承它的子类实现。
软件重用
软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,
1.继承的方式
通过继承建立了派生类与基类之间的关系,它是一种’是’的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师,调用用self.func()即可实现调用基类的函数。
2.组合的方式
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程。调用用a=class A(),a.func()即可实现调用其他类的函数。与调用普通类的方式一样。
继承:
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
继承主要有两大类功能:
一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能。
第一种通常有害,第二种比较常用。

本项目中也用到了第一种,BaseBizController为基类,定义了三种@staticmethod修饰的方法,继承后可不用实例化,直接引用,
class BizSingleControllerBase(BaseBizController)的get_model_risk_result方法

    def get_model_risk_result(self, company_name, is_refresh_main, is_refresh_network=False):
        """
        获取模型风险处理结果
        """
        company_features_ifc = self._get_company_features_interface()
        if isinstance(company_features_ifc, CompanyFeaturesIfc):
            self._cache_process(company_features_ifc, company_name, is_refresh_main, is_refresh_network)
        else:
            raise BizException(u'未实现指定接口')
        features_maybe

除此之外,还定义了8个运用abstract修饰的方法,即抽象类; 与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化,例如BaseBizController只能被class BizSingleControllerBase(BaseBizController)这样继承,不能被实例化,例如BaseBizController();
4. 抽象类与接口
区别:
#子类继承抽象类,但是必须定义read和write方法
#子类继承接口,不用必须定义read和write方法
接口:接口提取了一群类共同的函数,可以把接口当做一个函数的集合。然后让子类去实现接口中的函数。这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

抽象类:抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计 ;
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的;调用基类时子类必须实现的基类所有的抽象类,
类似:

 @abstractmethod
    def _get_risk_type(self):
        """
        获取风险类型
        """
    @staticmethod
    @abstractmethod
    def _save_to_db(company_features_supper, risk_res, f_d_do):
        """
        保存到数据库
        """

上面的BizSingleControllerBase又被作为基类,被BizShixinController(吊销、破产等)调用,BizShixinController必须实现BizSingleControllerBase中的8个抽象类方法,class BizShixinController(BizSingleControllerBase),基类实现总控的代码:

class BizSingleControllerBase(BaseBizController):
    """
    单节点预测控制器
    """

    def get_model_risk_result(self, company_name, is_refresh_main, is_refresh_network=False):
        """
        获取模型风险处理结果
        """

        company_features_ifc = self._get_company_features_interface()
        if isinstance(company_features_ifc, CompanyFeaturesIfc):
            self._cache_process(company_features_ifc, company_name, is_refresh_main, is_refresh_network)
        else:
            raise BizException(u'未实现指定接口')
        features_maybe = company_features_ifc.get_features_by_company_name_maybe(company_name)

        if features_maybe.is_empty():  # 评估运算
            # 准备模型输入对象
            f_d_do = self._get_api_features(company_name)

            # 多条件处理状态和返回结果
            prob_maybe = self._get_prob_maybe(company_name)
            if self._is_manual_intervention(f_d_do, prob_maybe):  # 符合人工干预条件
                logging.info(u'{} 人工干预结果'.format(company_name))
                prob = prob_maybe.get()
                status = bC.OUTPUT_STATUS_HUMAN_INTERVENTION
                risk_res = self._manual_intervention(company_name, status, prob, f_d_do)
            elif self._is_normal_predict(f_d_do, prob_maybe):  # 正常预测
                logging.info(u'{} 正常预测'.format(company_name))
                status = bC.OUTPUT_STATUS_PREDICT
                risk_res = self._normal_predict(company_name, status, f_d_do)
            else:  # 不预测
                logging.info(u'{} 不予预测'.format(company_name))
                status = self._get_no_predict_status(f_d_do)
                risk_res = self._no_predict_process(company_name, status, f_d_do)
            # 保存到数据库
            self._save_to_db(company_features_ifc, risk_res, f_d_do)
            return risk_res

        else:  # 读取数据库
            logging.info(u'{} 读取数据库缓存'.format(company_name))
            return features_maybe.get()
 @staticmethod
    @abstractmethod
    def _save_to_db(company_features_supper, risk_res, f_d_do):
        """
        保存到数据库
        """

注意调用:self._save_to_db(company_features_ifc, risk_res, f_d_do),即用@staticmethod修饰后,其类中的方法可以向被当做类的属性一样使用;不用将类实例化,再调用。因为通常python类中如何调用在类里定义的函数:先将类实例化,再调用。
(1)函数
  当函数定义好之后,可以直接调用。
  比如:def summ(add1,add2),那么可以直接调用,即:summ(1,2)
(2) 类
  类定义好之后,不能像函数一样直接调用,而需要间接调用。
  比如:class people,那么调用时,a=people(对象),之后,a.age()等等
(3) 模块
  将多个类放在同一个py下,比如放在model.py中,则import model即可调用
(4) 包
在site-package文件夹下创建一个文件夹,如:Kitchen
另外一些类的.py,都放入Kitchen文件中
在其中创建init.py文件,将显示import语句写入当中,如:from Omelet(方Omelet类的文件名Omelet.py) import Omelet(类名)。编程时,直接import Kitchen,Kitchen.xxx即可调用。

猜你喜欢

转载自blog.csdn.net/sinat_26566137/article/details/80791850