软件设计本质论(Essential Design) —白话面向对象

《Low Power Design Essential》读后笔记(一) 本文仅为个人娱乐分享,请勿用于其他用途 chapter 1 power and energy consumption analyze the different application domains from power perspective technology trends CMOS scaling design solutions key words: power dissipa... 阅读详情

软件设计本质论(Essential Design) —白话面向对象

 

转载时请注明出处:http://blog.youkuaiyun.com/absurd/

 

不同的人在谈面向对象编程(OOP)时所指的含义并不相同。有人认为任何采用图形界面的应用程序都是面向对象的。有人把它作为术语来描述一种特别的进程间通信机制。还有人使用这个词汇是另有深义的,他们其实是想说:“来啊,买我的产品吧!”我一般不提OOP,但只要提到,我的意思是指使用继承和动态绑定的编程方式。 --《C++沉思录》

 

《C++沉思录》说的是十几年前的事了,现在大家对面向对象的回答已经是众口一词:封装、继承和多态。大家都知道,在面向对象中,一辆汽车是一个对象,汽车这个概念是一个类。汽车有漂亮的外观,把各种内部原理都隐藏起来了,司机不必知道它的内部工作原理仍然能开车,即使汽车随技术的进步不断升级,对司机也没有什么影响,这就是封装的好处。

 

汽车是交通工具的一种,汽车是一个类,交通工具也是一个类,而交通工具类包括了汽车类,从而具有更广泛的意义。这种从抽象到具体的关系就是继承关系,我们可以说汽车类继承了交通工具类,汽车类是交通工具类的子类,交通工具类是汽车类的父类。

 

作为交通工具,它肯定可以运动(move),从甲地运动到乙地,就起到了交通的作用。轮船是一种交通工具,所以轮船类也是交通工具类的子类。同样是运动,轮船的运动和汽车的运动方式肯定有所不同,这样以不同的方式完成同样的功能就叫多态。

 

关于对象:对象就是某一具体的事物,比如一个苹果, 一台电脑都是一个对象。每个对象都是唯一的,两个苹果,无论它们的外观有多么相像,内部成分有多么相似,两个苹果毕竟是两个苹果,它们是两个不同的对象。对象可以是一个实物,也可能是一个概念,比如某个苹果对象是实物,而一项政策可能就是一个概念性的对象了。

 

关于类:对象可能是一个无穷的集合,用枚举的方式来表示对象集合不太现实。抽象出对象的特征和功能,按此标准将对象分类,这就引入类的概念。类就是一类事物的统称,类实际上就是一个分类的标准,符合这个分类标准的对象都属于这个类。当然,为了方便起见,通常只需要抽取那些,对当前应用来说是有用的特征和功能。

 

关于抽象类:类是对对象的抽象,比如,苹果是对所有具体的苹果的抽象。如果我们对苹果这个类进行一步抽象,可以得到一个水果类。这种对类本身进行抽象而得到的类,就是抽象类。抽象类不像普通类,它是没有对象与之对应的。像苹果类,你总是可以拿到一个叫苹果的东西,而对于水果类,根本没一个真正叫水果的东西。你可以说一个苹果是一个水果,从逻辑上讲没有错,但没有什么意义。一般在程序中,抽象类是不能实例化的。

 

关于面向对象:面向对象就是以对象为中心。为什么不说是面对类,而说是面向对象呢?类是对象的集合,考虑类实际上也是在考虑对象,有时甚至并不严格的区分它们。所以说面向对象一词比面向类更确切。

 

既然以对象为中心,面向对象所考虑的内容自然是对象、对象间的协作、对象的分类、类之间的关系等等,由此引申了出几个重要的概念。

 

1.         封装

what:对象也有隐私,对象的隐私就是对象内部的实现细节。要想对象保持良好的形象就要保护好对象隐私,所谓的封装其实就是保护对象隐私。当然,没有人能完全隐藏自己的隐私,比如你去转户口时,你不得不透露自己的家庭信息和健康状况。另外,在不同的场合所透露隐私的数量也不一样,朋友和家人可能会知道你更多隐私,同事次之,其他人则知道得更少。面向对象也考虑了这些实际的情况,所以像C++之类的语言有public/private/protected/friend等关键字,以适应于不同的情况。

 

why:封装可以隔离变化。据以往的经验,我们知道内部实现是容易变化的,比如电脑在不断的升级,机箱还是方的,但里面装的CPU和内存已是今非昔比了。变化是不可避免的,但变化所影响的范围是可以控制的,不管CPU怎么变,它不应该影响用户使用的方式。封装是隔离变化的好办法,用机箱把CPU和内存等等封装起来,对外只提供一些标准的接口,如USB插口、网线插口和显示器插口等等,只要这些接口不变,内部怎么变,也不会影响用户的使用方式。

 

封装可以提高易用性。封装后只暴露最少的信息给用户,对外接口清晰,使用更方便,更具用户友好性。试想,如果普通用户都要知道机箱内部各种芯片和跳线,那是多么恐怖的事情,到现在为止我甚至还搞不清楚硬盘的跳线设置,幸好我没有必要知道。

 

how:在C语言中,可以用结构+函数来模拟类的实现,而用这种结构定义的变量就是对象。封装有两层含义,其一是隐藏内部行为,即隐藏内部函数,调用者只能看到对外提供的公共函数。其二是隐藏内部信息,即隐藏内部数据成员。现在都建议不要对外公开任何数据成员,即使外部需要知道的数据成员,也只能通过函数获取。

 

在C语言中要隐藏内部函数很简单:不要它把放在头文件中,在C文件中定义时,前面加static关键字,每个类放在独立的文件中。这样可以把函数的作用范围限于当前文件内,当前文件只有类本身的实现,即只有当前的类自己才能看到这些函数,这就达到了隐藏的目的。

 

在C语言中要隐藏数据成员较为麻烦,它没有提供像C++中所拥有的public/protected/friend/private类似的关键字。只能通过一些特殊方法模拟部分效果,我常用的方法有两种。

 

其一是利用C的特殊语法,在头文件中提前声明结构,在C文件才真正定义它。这样可以把结构的全部数据信息都隐藏起来。因为外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这种方法的缺陷是不支持继承,因为子类中得不到任何关于父类的信息。如:

头文件:

struct _LrcPool;

typedef struct _LrcPool LrcPool;

 

LrcPool* lrc_pool_new(size_t unit_size, size_t n_prealloc_units);

void*    lrc_pool_alloc(LrcPool* thiz);

void     lrc_pool_free(LrcPool* thiz, void* p);

void     lrc_pool_destroy(LrcPool* thiz);

 

C文件:

struct _LrcPool

{

    size_t unit_size;

    size_t n_prealloc_units;

};

 

LrcPool* lrc_pool_new(size_t unit_size, size_t n_prealloc_units)

{

    LrcPool* thiz = LRC_ALLOC(LrcPool, 1);

       

    if(thiz != NULL)

    {  

        thiz->unit_size = unit_size;

        thiz->n_prealloc_units = n_prealloc_units;

    }

   

    return thiz;

}

 

其二是把私有数据信息放在一个不透明的priv变量中。只有类的实现代码才知道priv的真正定义。如:

头文件:

struct _LrcBuilder

{

    LrcBuilderBegin     on_begin;

    LrcBuilderOnIDTag   on_id_tag;

    LrcBuilderOnTimeTag on_time_tag;

    LrcBuilderOnLrc     on_lrc;

    LrcBuilderEnd       on_end;

    LrcBuilderDestroy   destroy;

 

    char priv[1];

};

 

 

C文件:

struct _LrcDumpBuilder

{

    FILE* fp;

};

 

typedef struct _LrcDumpBuilder LrcDumpBuilder;

LrcBuilder* lrc_dump_builder_new(FILE* fp)

{

    LrcDumpBuilder* data =  NULL;

    LrcBuilder* thiz = (LrcBuilder*)calloc(sizeof(LrcBuilder) + sizeof(LrcDumpBuilder), 1);

 

    if(thiz != NULL)

    {

        thiz->on_begin     = lrc_dump_builder_on_begin;

        thiz->on_id_tag    = lrc_dump_builder_on_id_tag;

        thiz->on_time_tag  = lrc_dump_builder_on_time_tag;

        thiz->on_lrc       = lrc_dump_builder_on_lrc;

        thiz->on_end       = lrc_dump_builder_on_end;

        thiz->destroy      = lrc_dump_builder_destroy;

        data = (LrcDumpBuilder*)thiz->priv;

        data->fp = fp != NULL ? fp : stdout;

    }

 

    return thiz;

}

 

2.         继承

what: 继承描述的是一种抽象到具体的关系。具体的东西继承了抽象的东西的特性,比如说,水果这个概念比苹果这个概念更抽象,其意义更具有一般性,而苹果这个概念则更具体,其意义更狭窄一些,在面向对象里,我们可以说苹果类继承了水果类。继承是指继承了父类的特性,继承本质是源于分类学,细的分类继承大分类的特性。

 

why: 继承描述了抽象到具体的关系,所以能够有效利用抽象这件武器来战胜软件的复杂性。抽象在实现中无处不在,类就是对事物的抽象,提到苹果你就想到苹果这一类事物,无需要关心其大小、颜色和成分,苹果这两个字就足够了。名不正则言不顺,言不顺则事不成,看来老夫子已经领悟到了抽象的威力。

 

继承不但利用了抽象的力量来降低系统的复杂性,它还提供了一种重用的方式。假设我们承认下列面这个继承关系,苹果继承了水果,水果继承了食物,如果我们已经知道什么是食物,什么是水果,在描述苹果时,没有必要去重复讲解食物和水果的概念了,这就是重用,重用了对水果和食物两个概念的理解。

 

how: 在C语言中实现继承很简单,可以用结构来模拟。这种实现基于一个明显的事实,结构在内存中的布局与结构的声明具有一致的顺序。我们知道在程序描述事物的特征时,主要通过数据变量描述事物的属性特征,如颜色、重量和体积等,用函数来描述事物的行为特征,和运动、成长和搏斗等。在C语言中实现继承的方式如:

struct  _GObject

{

  GTypeInstance  g_type_instance;

  volatile guint ref_count;

  GData         *qdata;

};

 

struct _GtkObject

{

  GObject parent_instance;

  guint32 flags;

};

 

struct _GtkWidget

{

  GtkObject parent_instance;

  guint16 private_flags;

  guint8 state;

  guint8 saved_state;

  gchar *name;

  GtkStyle *style;

  GtkRequisition requisition;

  GtkAllocation allocation;

  GdkWindow *window;

  GtkWidget *parent;

};

 

 

(GtkWidget继承GtkObject,GtkObject继承GObject)

      

继承在现实世界中应用很广,在程序里也是一样,甚至可以说是过度使用了。多年以前一些大师已经提出,优先使用组合而不是继承。主要原因有三点,首先是多级继承和多重继承太复杂了,失去了抽象带来的简洁性。其次是父类与子类之间共享太多信息,它们的耦合太紧密。三是父类与子类之间的关系在编译时就静态绑定了,很难做到在运行时多态。

 

现在一般都提倡,只继承接口不继承实现,通过组合达到代码重用的目的。在《设计模式》中是这样强调的,在MS的COM里也是这样做的。所以我基本上只使用接口继承,很少遇到什么麻烦,建议大家也遵循这一准则。

 

3.         多态

what: 尽管多态这个词本身就表明了它所代表的意义,但还是让初学者感到多少有些神秘。多态就是完成相同功能的多种方式,比如拿动物的运动来说吧,鸟的运动通常是飞,鱼的运动通常是游,陆上动物的运动通常是跑,同是运动,但方式不一样,这就是多态。不少人对多态的回答是,允许同名函数存在。这种回答显然没有抓住多态的本质。

 

why: 关于动物运动这个例子,可能无法展示多态的好处。我们来考虑另外一个多态的例子,U盘。U盘的技术含量可能不是很高,有很多厂家都在设计和生产,就是说U盘有多种不同的实现,这就是U盘的多态。U盘的多态性对消费者来说是有好处的,选择多了,你可以在价格、质量和外观等方式做出平衡,选择你中意的U盘。多态的前提是接口的一致性,否则多态造成的麻烦远胜于它带来的好处。不管U盘的体积、颜色和质量如何,它都必需遵循相应的USB标准,这些U盘在任何带USB接口的电脑上都可以使用。

 

how: 多态在C语言中通常用函数指针来实现,函数指针定义了函数的原型,即它的参数和返回值的描述,以及函数的意义,不同的函数可以有相同的函数原型,比如排序函数,无论是快速排序还是归并排序,它们的实现不一样,但函数原型可以一样。在不同的情况下,让函数指针到不同的函数实现上,这就实现了多态。下面的C语言例子:

 

       接口:

struct _LrcBuilder;

typedef struct _LrcBuilder LrcBuilder;

 

typedef LRC_RESULT (*LrcBuilderBegin)(LrcBuilder* thiz, const char* buffer);

typedef LRC_RESULT (*LrcBuilderOnIDTag)(LrcBuilder* thiz, const char* key, size_t key_length,

                    const char* value, size_t value_length);

typedef LRC_RESULT (*LrcBuilderOnTimeTag)(LrcBuilder* thiz, size_t start_time);

typedef LRC_RESULT (*LrcBuilderOnLrc)(LrcBuilder* thiz, const char* lrc, size_t lrc_length);

typedef LRC_RESULT (*LrcBuilderEnd)(LrcBuilder* thiz);

typedef LRC_RESULT (*LrcBuilderDestroy)(LrcBuilder* thiz);

 

struct _LrcBuilder

{

    LrcBuilderBegin     on_begin;

    LrcBuilderOnIDTag   on_id_tag;

    LrcBuilderOnTimeTag on_time_tag;

    LrcBuilderOnLrc     on_lrc;

    LrcBuilderEnd       on_end;

    LrcBuilderDestroy   destroy;

 

    char priv[1];

};

 

       实现一:

LrcBuilder* lrc_dump_builder_new(FILE* fp)

{

    LrcDumpBuilder* data =  NULL;

    LrcBuilder* thiz = (LrcBuilder*)calloc(sizeof(LrcBuilder) + sizeof(LrcDumpBuilder), 1);

 

    if(thiz != NULL)

    {

        thiz->on_begin     = lrc_dump_builder_on_begin;

        thiz->on_id_tag    = lrc_dump_builder_on_id_tag;

        thiz->on_time_tag  = lrc_dump_builder_on_time_tag;

        thiz->on_lrc       = lrc_dump_builder_on_lrc;

        thiz->on_end       = lrc_dump_builder_on_end;

        thiz->destroy      = lrc_dump_builder_destroy;

        data = (LrcDumpBuilder*)thiz->priv;

        data->fp = fp != NULL ? fp : stdout;

    }

 

    return thiz;

}

       实现二:

      

LrcBuilder* lrc_default_builder_new(void)

{

    LrcDefaultBuilder* data =  NULL;

    LrcBuilder* thiz = (LrcBuilder*)calloc(sizeof(LrcBuilder) + sizeof(LrcDefaultBuilder), 1);

 

    if(thiz != NULL)

    {

        thiz->on_begin     = lrc_default_builder_on_begin;

        thiz->on_id_tag    = lrc_default_builder_on_id_tag;

        thiz->on_time_tag  = lrc_default_builder_on_time_tag;

        thiz->on_lrc       = lrc_default_builder_on_lrc;

        thiz->on_end       = lrc_default_builder_on_end;

        thiz->destroy      = lrc_default_builder_destroy;

        data = (LrcDefaultBuilder*)thiz->priv;

    }

 

    return thiz;

}

 

类的三个层次:

类这个概念比较微妙,即使在软件开发领域,不同的人提到这个概念所指的内容也不一样。一些大师早就注意到了这一点,为了让这个概念在不同情况下,具有较准确的意义,他们建议从三个层次看待类这个概念:

 

1.         概念层(Conceptual)

这是一个较高的层次,通常在进行领域分析时,为了建立概念模型时使用。这时使用的术语是现实世界中的术语,而不是软件开发中的术语。在这个层次,类只是一个概念,加上一些不太严谨的特征说明,甚至只有一个名称。尽管它往往与软件开发中的类一一对应,便这种映射并不一定是直接的。

 

2.         规格层(Specification)

在这个层次,类已经是属于软件开发范畴了,但主要关注的是类的接口,而不是类的实现。此时你可能想到它的一组接口函数,而不关心这些函数是如何实现的。

 

3.         实现层(Implementation)

在这个层次,我们才真正关注类的实现,此时你可能会想到一些用某种语言写成的函数体,定义的成员变量等等。

 

面向对象的好处:

面向对象已经征服了软件开发的绝大部分领域,近几年来出现的面向方面的编程(AOP)、产生式编程(GP)和面向组件的开发等等,都提出了一些新的思维,在某些方面大提高了开发效率,但它们并非是取代了面向对象,相反是对面向对象的补充和完善,面向对象始终稳坐第一把交椅。

 

面向对象到底有何德何能,它凭借什么取代面向对程呢?封装、继承和多态到底有何种魔力,吸引众多的高手去完善它,让布道者们不厌其烦的颂扬它呢?归根结底,面向对象会带来两个好处,这两个好处正是设计者们一直在追求的:

 

1.         降低系统的复杂度。

众所周知,随着硬件的飞速发展,计算机的计算能力越来越强大,人们对软件期望也越来越高,而软件复杂度又与它的规模成指数倍数增长。软件复杂度可以说是软件开发的第一大难题,我们可以轻而易举的写出5000行代码,而面对100万行代码规模的软件,会有点让人觉得人的智力是多么有限。

 

而面向对象正是降低系统复杂度的好方法。首先它按类来组织系统,把系统分成几个大的部分,每个部分又由更小的子类组成,如此细分下去直到我们能轻易实现它为此,这种分而治之的方法符合人类解决复杂问题的习惯。

 

其次是它采用从抽象到具体的顺序来把握事物,抽象让我们用少量精力先掌握事物的共性,然后再去研究事物更具体的特性,这种逐渐细化的方法也是符合人类解决复杂问题的习惯的。

 

2.         隔离变化。

需求变化和技术变化也是软件开发所面临的两大难题。用户似乎从来不知道什么是他们真正的需求,或许他们真正的需求也是在变化的。技术可谓日新月异,我们不断的发明新技术,这些技术帮我们提高了生产力。但有时新技术也会砸到自己的脚,为了运用这些新技术,我们要花更多时间学习和工作。或者说创新只是满足了少数人的乐趣,让多数人吃了苦头。

 

只有变化才是永恒的,诅咒变化无济于事,面对它并搞掂它才是正途。大师也建议我们去拥抱变化,而不是逃避变化。面向对象正是拥抱变化的银弹之一,它不是尝试阻止变化的发生(对此谁也无能为力),而是努力去隔离变化。与整体比较,变化的部分毕竟只占很小的分量,如果这些变化被隔离开了,它不影响不变的部分的,变的部分独立变化,不会牵一发而动全身,这可以大大减少变化引起的麻烦。针对接口编程而不是针对实现编程,这是面对象的精髓,也是拥抱变化的良方。

 

~~~end~~

 

 
软件设计本质论--面向对象.pdf 软件设计本质论--面向对象,详细的讲解,容易理解 立即下载

相关推荐

5分钟搞定SNMP工具安装:从Linux到Windows的snmpwalk/snmpget全攻略

本文提供了SNMP工具(snmpwalk/snmpget)在Linux和Windows系统上的快速安装与使用指南,涵盖从基础安装到高阶应用的全面解析。通过详细的命令示例和故障排查技巧,帮助用户快速掌握网络设备监控与诊断的核心技能,提升运维效率。

weixin_29248313的博客 555

软件设计的基本原理

1.模块化 模块是程序中数据说明、可执行语句等程序对象的集合,或者是单独命名和编址的元素。在软件体系结构中,模块是可组合、可分解和可更换的单元。 模块化是指解决一个复杂问题时自顶向下逐层把软件系统分成若干模块的过程。每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功能。 开发一个大而复杂软件系统,将它进行适当的分解,不但可降低其复杂性,还可减少开发工作量,从而降低开发成本,提高软件生产率。这是模块划分的依据。 2.抽象 抽象是认...

迷麟的博客 5184

解决相同型号USB设备在Windows系统中重复枚举问题

本文详细解析了Windows系统中相同型号USB设备重复枚举问题的成因及解决方案。通过修改注册表、使用PsTools工具清除设备记录以及编程实现自动化处理等方法,有效解决设备识别混乱问题,特别适用于自动化测试和工业设备管理场景。

weixin_42561040的博客 565

01 | 软件设计到底是什么?

今天,我们学习了软件设计到底是什么,它应该包括“模型”和“规范”两部分:模型,是一个软件的骨架,是一个软件之所以是这个软件的核心。模型的粒度可大可小。我们所说的“高内聚、低耦合”指的就是对模型的要求,一个好的模型可以有效地隐藏细节,让开发者易于理解。模型是分层的,可以不断地叠加,基于一个基础的模型去构建上一层的模型,计算机世界就是这样一点点构建出来的。规范,就是限定了什么样的需求应该以怎样的方式去完成。它对于维系软件长期演化至关重要。关于规范,常见的两种问题是:一个项目缺乏显式的、统一的规范;

qq_37756660的博客 2112

手把手教你用Cadence Virtuoso完成LNA全套仿真:基于SpectreRF手册的实战补充

本文详细指导如何使用Cadence Virtuoso和SpectreRF完成LNA的全套仿真,涵盖噪声仿真、增益压缩、THD分析及双音IP3测量等关键步骤。针对官方手册中的常见问题,提供了12个实战解决方案,包括hbnoise函数选择、双音信号源配置等,帮助工程师高效完成射频IC设计。

weixin_29102619的博客 523

qcom bypass node介绍

介绍qcom bypass node,以及如何让其生效

haodada1226的博客 2042

软件即抽象

本文关键字:抽象是软件的本质,设计是编程的本质 首先,什么是编程,这或许要先问,什么是软件,因为具体编程就是一种“在某平台下,使用某语言,针对解决某个需求进行实现,某个问题进行解决,由程序团队完成最终递交给客户并维护的整个过程,产生的结果就叫软件”,人们只注意到了作为结果的软件,但其实这里提到了很多实体和对象 ----- 整个软件和软件开发,它是一种寄涉众多的人类工程,每一个都不可分别而论。 具体到工业层次的软件开发和应用上,人们最终追求的始终是如何控制软件的生产周期,降低成本。更灵活地处理新出现的需求和软

minlearn's techrepos 1250

CocosCreator 面试题(十五)Cocos Creator如何内置protobuf JS版本?

接着,它创建了一个 Player 对象,并使用 protobuf.js 提供的 API 对其进行序列化和反序列化操作。其中,name 和 level 是普通的字段,items 是一个 repeated 字段,表示它可以包含多个值。在 Cocos Creator 中使用 protobuf.js,我们需要先加载 .proto 文件,然后使用 protobuf.js 提供的 API 进行序列化和反序列化操作。JSON和XML是文本格式,更易于阅读和调试,而且在对人类友好的接口和数据交换上更为常见和广泛支持。

w风雨无阻w的专栏 2628

软件设计本质论(Essential Design) —从链表设计说起

软件设计本质论(Essential Design) —从链表设计说起 转载时请注明出处:http://blog.youkuaiyun.com/absurd/ 大师说,软件设计不过是在适当的时候做出适当的决策罢了。对此我深以为然,好的设计就是做出了正确决策。然而,在多种互相竞争的因素下,要好做出正确的决策可不是件容易的事!本文以一个双向链表的设计为例,阐述一下软件设计为什么这样困难。 双

国产开源 GUI 引擎 AWTK 7844

Open Dynamics Engine(ODE)物理引擎基础教程(I)——特点介绍

下一教程 Open Dynamics Engine(ODE)物理引擎基础教程(II)——相关概念 (在这一教程中将学习刚体、关节、碰撞的概念在ODE中的特点) 本文结构引言介绍特点使用ODE总结 引言 本文翻译自ODE官方教程英文版,有些地方增加了自己的理解。这一节介绍ODE的相关概念。 基础教程英文原版链接【http://ode.org/wiki/index.php?title=Manua...

腿足机器人领域 1677

军品研制过程评审活动-(一)论证阶段

军品研制过程评审活动-(一)论证阶段

Abel的博客 3815

软件设计本质论(Essential Design) —序

软件设计本质论(Essential Design) —序 转载时请注明出处:http://blog.youkuaiyun.com/absurd/ 标题可能让人觉得有些自负,这并非出于我的本意。为了避免冒犯一些挑剔的网友,对此我先做一点说明。本质这个词历来与哲学的关系比较紧密,本质与现象对应,于是本质似乎都是一些极端抽象的东西。而近年来出版的一些书籍,如《COM本质论》、《.NET本质论第1卷:公共...

jinghuainfo 391

【图像去噪】论文复现:灵感源自MAE!进一步解决BSN的局限性,破坏真实噪声的空间相关性!AMSNet的Pytorch源码复现,跑通源码,原理详解!

论文题目:Asymmetric Mask Scheme for Self-Supervised Real Image Denoising —— 自监督真实图像去噪的非对称掩码方案【图像去噪】论文精读:Asymmetric Mask Scheme for Self-Supervised Real Image Denoising(AMSNet)AMSNet是基于PyTorch Lightning CLI深度学习框架编写的,比较适合复杂的大型任务,复用很方便,但是安装和环境配置问题太多。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 546

软件设计本质论 Essential Design —白话面向对象

软件设计本质论 Essential Design —白话面向对象

jggyff的博客 296

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

0114__软件设计本质论(Essential Design) —白话面向对象

软件设计本质论(Essential Design) —白话面向对象_essential design software-优快云博客

行潇 310

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

软件设计本质论(Essential Design)—白话面向对象

转载时请注明出处:http://blog.youkuaiyun.com/absurd/ 不同的人在谈面向对象编程(OOP)时所指的含义并不相同。有人认为任何采用图形界面的应用程序都是面向对象的。有人把它作为术语来描述一种特别的进程间通信机制。还有人使用这个词汇是另有深义的,他们其实是想说:“来啊,买我的产品吧!”我一般不提OOP,但只要提到,我的意思是指使用继承和动态绑定的编程方式。

andyhuabing的专栏 1718

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

软件设计本质论(Essential Design) —白话面向对象 (转注:关于c语言实现封装继承多态的一堆博文)

软件设计本质论(Essential Design) —白话面向对象 分类: 23.设计本质论系列 2006-08-15 21:424361人阅读 评论(11)收藏 举报 软件设计本质论(Essential Design)—白话面向对象   转载时请注明出处:http://blog.youkuaiyun.com/absurd/   不同的人在谈面向对象编程(OOP)时所指的含义并不相同。有人

苏嵌——杭天龙 1909

软件设计本质论 Essential Design —序

软件设计本质论 Essential Design —序

jggyff的博客 391

软件设计本质论 Essential Design —从链表设计说起

软件设计本质论 Essential Design —从链表设计说起

jggyff的博客 249

Content of "Essential Software Test Design"

Content of "Essential Software Test Design" 2015-11-16 PART I 7 TEST DESIGN TECHNIQUES: AN OVERVIEW PART II 8 THE OVERARCHING PROCESS OF TEST DESIGN 12 FROM USE CASES TO TEST CASES 13 STATE ...

weixin_33971130的博客 173
上一篇: 试玩UML(User Mode Linux)
下一篇: 构建带内存错误检查的gcc
李先静
博客等级 码龄23年 2万+粉丝 846原创
评论 11
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值