杂七杂八(2)——可以把重写看成是对函数的“重新赋值”

简介:
杂七杂八(2)——可以把重写看成是对函数的“重新赋值”
小序:
如此“不严谨”、如此“谬误”的标题,一看就是找骂的!
正文:
前几天在读代码的时候,发现代码里有一些函数,函数体是空的。起初是以为那是为了实现一个Interface或者是一个Abstract类而实际上又没什么实际用处才这么做的,于是没太当回事。今天Anstinus同学指导我写代码的时候,又用到这个“技术”,我才明白——这些函数体为空的函数都被声明为了virtual的,实际上“故意”留给子类去重写的(God~~哪个virtual函数不是“故意”留给子类的)。这个函数体为空的函数,在父类的某个逻辑流程中被调用了,只是因为函数体为空,而什么事都没有做。等到了子类中,一旦子类对这个函数进行了重写,就会个性化地影响到这个逻辑流程。
这种用法之所以特殊,是因为以前我使用virtual函数的时候,注重的是“对原有功能的改写”,这次使用virtual是对一个“根本没有功能”的函数的“功能”进行“改写”。这个感觉像什么呢?呃……以前的改写应该算做“从1到2”,而这次改写应该是“从0到1”。回到我们的标题——如果把函数看成是一个变量,函数的功能(函数体)就是它的值,而重写(override)就好像是对函数进行重新赋值一样,这样,在不同的继承级别上,函数就能获得不同的“值”。
在给出代码之前插一句:无论是变量名、函数名、类名……(简言之就是标识符啦),实际上都是指向一个内存地址,只是变量名指向的内存地址(再加上一个偏移量)里装的是“数值”,数据所占的内存块儿的大小由变量的类型决定;函数名指向的内存地址(再加上一个偏移量)里装的是一组CUP的指令;类名指向的内存地址里装的是这个类(无论是类还是实例)所共用的东西的清单(Table),所以,类实际上是一个作用域(Scope)。
OK,让我们看看今天我遇到的问题的简化版本——感谢Anstinus同学又教会我新东西:)
using  System;

namespace Sample
{
                class AAA
                {
                                public void DoSomething()
                                {
                                                Console.ForegroundColor = ConsoleColor.Yellow;
                                                Console.WriteLine("Do something...");

                                                // Something OPTIONAL
                                                this.DoSomethingOptional(); // 
调用了,但在 AAA 类中,实际上什么事也没做

                                                Console.ForegroundColor = ConsoleColor.Yellow;
                                                Console.WriteLine("Do other things...");
                                }

                                protected virtual void DoSomethingOptional()                                           // 
函数体是空的
                                {
                                }
                }

                class BBB : AAA
                {
                                protected override void DoSomethingOptional()
                                {
                                                Console.ForegroundColor = ConsoleColor.Green;
                                                Console.WriteLine("http://blog.csdn.net/FantasiaX"); 
                                }
                }

                class CCC : AAA
                {
                                protected override void DoSomethingOptional()
                                {
                                                Console.ForegroundColor = ConsoleColor.Magenta;
                                                Console.WriteLine("Some logic in CCC..."); 
                                }
                }

                class Program
                {
                                static void Main(string[] args)
                                {
                                                AAA aaa = new AAA();
                                                BBB bbb = new BBB();
                                                CCC ccc = new CCC();

                                                aaa.DoSomething();
                                                Console.WriteLine();
                                                bbb.DoSomething();
                                                Console.WriteLine();
                                                ccc.DoSomething();
                                }
                }
}

===============================
这是不是最佳方案?
实际上,几乎任何一个逻辑我们都有不止一种办法来实现它。就拿这个例子而言,完全可以定义一个
delegate void MyDelegate();
并为AAA类声明一个MyDelegate类型的field:
 
 
if (optionalThing != null)
{
        optionalThing();
}
这样,在子类中,随便你用什么方法,只要把恰当的函数名赋值给optionalThing就可以了。这种方法比起上面代码中的方法要灵活得多、自由得多!
你可能会问:那为什么项目中却没有采用这种方法呢?
原因有如下几个——
  • 为了使用这种方法,需要额外定义用途专一的delegate和成员变量,增加了日后维护成本
  • 两种方法在代码量上没有太大差别
  • 代码中的方法约束力比较强,这样,在子类中的实现看起来会比较一致,实现的时候和日后维护的时候成本较低(实际上,作为下游程序员,我也更喜欢这种方式,copy-paste就能解决很多问题)
 所以你看,有时候“缺点”反而是优点!
OK,今天就写到这儿~~做饭去喽!今天是西红柿炒鸡蛋:D









本文转自 水之真谛 51CTO博客,原文链接:http://blog.51cto.com/liutiemeng/95260,如需转载请自行联系原作者
目录
相关文章
|
应用服务中间件 JavaScript 虚拟化
阿里云香港轻量应用服务器介绍与测评:月付24元/30Mbps带宽/1TB流量
阿里云香港24是阿里云推出了一款非常优惠的香港的轻量应用服务器,每个月只需要24元,流量有1T,30M的带宽,国内延迟非常低,联通和移动是直连,电信去程ntt,回程cn2,性价比非常高。本文详细介绍这个方案的配置以及做一个简单的测评。
34388 0
|
弹性计算 监控 安全
阿里云服务器自带多少DDoS防护?小编为你详细揭秘!
阿里云服务器自带多少DDoS防护?小编为你详细揭秘!
|
存储 数据库 数据安全/隐私保护
本地文件内容搜索神器AnyTXT Searcher如何搭建与远程访问
本地文件内容搜索神器AnyTXT Searcher如何搭建与远程访问
870 0
|
NoSQL Java API
SpringBoot项目中防止表单重复提交的两种方法(自定义注解解决API接口幂等设计和重定向)
SpringBoot项目中防止表单重复提交的两种方法(自定义注解解决API接口幂等设计和重定向)
1755 0
|
SQL druid Java
SpringBoot内置数据源-持久化-数据库
SpringBoot内置数据源-持久化-数据库
SpringBoot内置数据源-持久化-数据库
|
人工智能 智能设计 云计算
阿里云LOGO在线设计智能生成网址入口
阿里云LOGO在线设计,阿里云logo生成器,阿里云logo智能生成网址入口,阿里云logo在线设计,阿里云logo智能设计一键生成海量LOGO可供选择,阿里云百科分享阿里云LOGO设计生成网址链接以及使用方法,智能LOGO设计,仅需3步,10秒生成,AI匹配海量logo,商用无忧
6886 0
阿里云LOGO在线设计智能生成网址入口
|
JSON 前端开发 安全
SpringCloud Gateway API接口安全设计(加密 、签名、安全)(二)
SpringCloud Gateway API接口安全设计(加密 、签名、安全)(二)
SpringCloud Gateway API接口安全设计(加密 、签名、安全)(二)
|
缓存 JSON IDE
Clang Module 内部实现原理及源码分析
钉钉工程开始支持Swift,在适配clang module的过程中,遇到了各种各样的编译问题,为了弄清楚这些编译失败的真正原因,以及clang module的最佳实践,决定通过深入阅读clang module的实现代码,来解开这些谜团。
1508 0
Clang Module 内部实现原理及源码分析
|
存储 缓存 PHP
Android | Compose状态管理
Android | Compose状态管理
|
传感器 编解码 监控
青果智能摄像机评测:麻雀虽小,五脏俱全
近几年智能硬件逐渐融入生活中的方方面面,受到了越来越多的消费者关注。就拿智能摄像机来说,作为智能家居中的一个重要角色,智能摄像机肩负着安保监控的重要使命。而各大厂商也纷纷推出了各自的智能摄像头试图抢占这个重要的市场。
1616 0
青果智能摄像机评测:麻雀虽小,五脏俱全