起名C#基础连串第4篇

前言:
完全是本人在攻读进度中记录的笔记,只不过分享一下让广大刚开头学习.net编程的人可以高效的学会C#语言

1. 怎么组件化这么难做

Web应用的组件化是二个很复杂的话题。

在大型软件中,组件化是一种共识,它一面提升了开销功用,另一方面降低了维护花费。不过在Web前端这么些领域,并没有很通用的零件方式,因为缺乏二个豪门都能肯定的贯彻格局,所以重重框架/库都落到实处了上下一心的组件化方式。

前端圈最喜爱于造轮子了,没有哪位其他领域能出现这么混乱而蓬勃的光景。这一派说明前端领域的成立力很起劲,另一方面却声明了根基设备是不完善的。

自身早就有过如此二个类比,表明某种编程技术及其生态提升的多少个等级:

最初的时候人们忙着补全各样API,代表着他们持有的事物还很不足,必要在言语跟基础设备上一而再周详然后就从头种种方式,标志他们做的东西渐渐变大变复杂,须求更好的协会通晓后就是各项分层MVC,MVP,MVVM,(++MV*)之类,可视化开发,自动化测试,团队一起系统等等,表明敬重生产成效了,相当于所谓工程化
那么,比较那三个等级,看看关心那二种东西的人口,觉得Web发展到哪一步了?

细节的话,几乎是模块化和组件化标准即将大规模落地(好坏先不论),各种API也大约齐备了,终于见到起飞的盼望了,各样框架几年内会有丰富强力的洗牌,若是不考虑老旧浏览器的拖累,这几个洗牌进程将大大加速,然后才能释放Web前端的产能。

只是大家必须注意到,将来这个即将普及的正统,很多都会给前边的工作带来改变。用工业系统的发展史来比较,前端领域方今正处在蒸汽机发明从前,早期机械(比如《木兰辞》里面的机杼,紧若是动力与资料比较原始)已经推广的这么二个品级。

据此,从这么些角度看,很多框架/库是会化为乌有的(专门做模块化的英特尔和CMD相关库,专注于条件DOM接纳器铺垫的少数库),一些则必须开展改制,还有局地受的震慑会比较小(数据可视化等巢倾卵破趋势),可以有时机沿着自个儿的方向持续形成。

  1. 多态的片段认证

2. 标准的变革

对于这类东西的话,能博得广泛民众根基的关键在于:对今后的标准有怎样的迎合程度。对前者编程格局可能导致重大影响的正儿八经有这几个:

1 module
2 Web Components
3 class
4 observe
5 promise

代码laycode –
v1.1

module的题目很好了然,javascript第一次有了语言上的模块机制,而Web
Components则是预订了依照泛HTML种类打造组件库的措施,class增强了编程体验,observe提供了数量和表现分离的一种理想艺术,promise则是时下前端最风靡的异步编程形式。

这中间只有多个东西是绕可是去的,一是module,一是Web
Components。前者是模块化基础,后者是组件化的基础。

module的尺度,紧要影响的是一些英特尔/CMD的加载和血脉相通管理种类,从这么些角度来看,正如seajs团队的@afc163
所说,不管是AMD依然CMD,都过时了。

模块化相对来说,迁移还比较便于,基本只是纯逻辑的包裹,跟速龙只怕CMD相比较,包装格局具有变更,但组件化就是个比较费劲的题材了。

Web Components提供了一种组件化的推荐方法,具体来说,就是:

通过shadow DOM封装组件的内部结构 通过Custom Element对外提供组件的标签
通过Template Element定义组件的HTML模板 通过HTML
imports控制组件的看重加载
那二种东西,会对现有的各个前端框架/库暴发很了不起的影响:

出于shadow
DOM的面世,组件的内部贯彻隐藏性更好了,每种组件尤其独立,不过那使得CSS变得很破碎,LESS和SASS那样的样式框架面临重大挑衅。
因为组件的隔离,每一种组件内部的DOM复杂度下降了,所以接纳器大部分处境下得以界定在组件内部了,常规采取器的复杂度下落,这会导致人们对jQuery的依赖下落。
又因为零部件的隔离性压实,致力于建立前端组件化开发方式的各个框架/库(除Polymer外),在融洽的组件完成方式与业内Web
Components的构成,组件之间数据模型的共同等难题上,都遇到了异样的挑衅。
HTML
imports和新的零部件封装格局的使用,会导致前边常用的以javascript为中央的各项组件定义形式不上不下,它们的依靠、加载,都面临了新的挑衅,而鉴于全局作用域的收缩,请求的联结变得紧巴巴得多。

 (1) 多态就是为了程序的可扩充性

3. 立刻最风靡的前端组件化框架/库

在二零一四年终那么些时刻点看,前端领域有八个框架/库引领时髦,那就是Angular,Polymer,React(排行依照首字母),在和讯的那篇2016年末有啥样相比较火的 Web
开发技术?里,作者大体回答过局地点,其余几人情人的答案也很值得看。关于这三者的底细解析,侯振宇的那篇讲得很好:二零一六前端框架何去何从

大家得以见见,Polymer这几个东西在那上头是有天赋优势的,因为它的大旨驰念就是依照Web
Components的,相当于说,它基本没有设想怎么样缓解日前的难点,间接以未来为进步势头了。

React的编程格局其实不必专程考虑Web标准,它的搬迁开支并不算高,甚至是因为其已毕机制,屏蔽了UI层完成格局,所以大家能看出在native上的运用,canvas上的运用,那都以与基于DOM的编程形式大为不一致的,所以对它来说,处理Web
Components的包容难点要在封装标签的时候消除,反正从前也是要卷入。

Angular
1.x的本子,可以说是跟同时期的大部分框架/库一样,对前景专业的十分基本没有考虑,不过再度规划之后的2.0本子对此有了重重衡量,变成了激进变更,突然就成为3个前途的东西了。

那五个东西各有千秋,在可以预感的几年内将会鼎足三分,可能还会有新的框架出现,能依然不能够比那多少个流行就难说了。
其余,原Angular 2.0的分子罗布艾森berg创造了和睦的新一代框架aurelia,该框架将变成Angular
2.0精锐的竞争者;(++同时,来自尤雨溪VueJS也在不久以往大放光彩)。

 (2)多态的利用:将差其他对象当作父类来看,屏蔽掉种种对象间的例外,写出通用代码,做出通用编程,同样调用差别结果,以适应须求的不停变动

4. 前端组件的复用性

看过了已有的有个别东西之后,大家可以大致来切磋一下前端组件化的一些视角。若是我们有了某种底层的机件机制,先不管它是浏览器原生的,可能是某种框架/库已毕的预订,未来打算用它来做一个特大型的Web应用,应该怎么做吗?

所谓组件化,核心意思莫过于提取真正有复用价值的事物。这怎么样的事物有复用价值啊?

1 控件
2 基础逻辑功能
3 公共样式
4 稳定的业务逻辑
5 对于控件的可复用性,基本上是没有争议的,因为这是实实在在的通用功能,并且比较独立。

代码laycode –
v1.1

基础逻辑功用主要指的是一些与界面毫无干系的东西,比如underscore那样的协理库,或然部分校验等等纯逻辑成效。

公物样式的复用性也是相比较便于认同的,因而也会有bootstrap,foundation,semantic这么些东西的风靡,不过它们也不是纯粹的样式库了,也暗含一些小的逻辑封装。

终极一块,也等于事情逻辑。这一块的复用是存在诸多冲突不休的,一方面是,很两人不认同业务逻辑也急需组件化,另一方面,那块东西到底怎么着去组件化,也很要求思想。

除开上边列出的那几个之外,还有多量的事务界面,这块东西很扎眼复用价值很低,基本不设有复用性,但如故有过多方案中把它们“组件化”了,使得它们变成了“不持有复用性的组件”。为啥会出现这种景色呢?

组件化的真相目标并不一定是要为了可复用,而是提高可维护性。这点正如面向对象语言,Java要比C++纯粹,因为它不允许例外意况的出现,连main函数都必须写到某些类里,所以Java是纯面向对象语言,而C++不是。

在我们那种状态下,也可以把组件化分为:全组件化,局地组件化。怎么明白那七个东西的分化吧,有人问过js框架和库的分别是怎么样,一般的话,有某种较强约定的事物,称为框架,而约定比较松散的,称为库。框架很多都以有全组件化理念的,比如说,很多年前就涌出的ExtJS,它是全组件化框架,而jQuery和它的插件种类,则是部分组件化。所以用ExtJS写东西,不管写什么都以基本上一样的写法,而用jQuery的时候,大部分地点是原始HTML,哪个地方需求有个别分裂的事物,就只在那么些地点调用插件做一下特殊化。

对此五个有早晚范围的Web应用来说,把具备东西都“组件化”,在管理上会有较大的便利性。小编举个例子,同样是编写代码,短代码鲜明比长代码的可读性更高,所以重重语言里会指出“1个措施一般不要领先多少行,八个类最好永不跨越多少行”之类。在Web前端这么些系统里,javascript那块是做得相对较好的,今后入门水平的人,也早就很少会有把一堆js都写在一齐的了。CSS那块,近日在SASS,LESS等框架的引领下,也渐渐往模块化方面进步,否则直接编写bootstrap那种css,会十分难受。

以此时候我们再看HTML的局地,如若不考虑模板等技能的施用,有个别界面光布局代码写起来就可怜多了,像有个别表单,都急需一层套一层,很多简约的表单元素都亟待套个三层左右,更不必说某个有盘根错节布局的东西了。越发是成套系统单页化之后,界面的header,footer,各样nav大概aside,很大概都有自然复杂性。要是这个东西的代码不作切分,那么主界面的HTML一定相比较难看。

咱俩先不管用什么样方法切分了,比如用某种模板,用类似Angular中的include,只怕Polymer,React中的标签,恐怕直接采纳原生Web
Components,同理可得是把一块一块都拆开了,然后包涵进来。从那几个角度看,这几个拆出去的东西都像组件,但假若从复用性的角度看,很或者半数以上东西,每一块都惟有贰个地点用,压根没有复开支。那几个拆出去,纯粹是为了使得全部工程易于管理,易于维护。

那儿大家再来关心不一样框架/库对UI层组件化的处理形式,发现有多少个体系,模板和函数。

模板是一种很宽泛的东西,它用HTML字符串的形式表明界面的原来结构,然后通过代入数据的法子转变真正的界面,有的是生成靶子HTML,有的还生成各个风云的电动绑定。前者是静态模板,后者是动态模板。

除此以外有一对框架/库偏爱用函数逻辑来生成界面,早期的ExtJS,以后的React(它其中依旧可能行使模板,而且对外提供的是组件创立接口的愈来愈封装——jsx)等,那种完毕技术的优势是见仁见智平台上编程体验一致,甚至可以给每一种平台封装相同的机件,调用方轻松写一份代码,在Web和见仁见智Native平台上可用。但那种办法也有相比费心的地点,这就是界面调整比较繁琐。

正文前面部分引用侯振宇的那篇作品里,他指出这一个标题:

如何能把组件变得更易重用? 具体一点:

自家在用某些组件时索要重新调整一下组件里面元素的顺序咋办?
小编想要去掉组件里面某一个因素咋办? 怎样把组件变得更易增加? 具体一点:
业务方不断要求给组件加效果如何是好?
为此,还提出了“模板复写”方案,在这或多或少上自家有两样观点。

咱俩来看看哪些把贰个政工界面切割成组件。

有这般3个粗略场景:一个雇员列表界面包蕴多个部分,雇员表格和用于填写雇员音讯的表单。在这几个情景下,存在哪些组件?

对此这几个题材,主要存在三种倾向,一种是一味把“控件”和相比较有通用性的事物封装成组件,别的一种是整个应用都组件化。

对前一种办法来说,那之中只设有数量表格这么二个零件。
对后一种情势来说,那中间有只怕存在:数据表格,雇员表单,甚至还包蕴雇员列表界面这么二个更大的零件。

那两种办法,就是我们从前所说的“局地组件化”,“全组件化”。

作者们前边提到,全组件化在管制上是存在优势的,它可以把不一样层面的事物都搞成类似结构,比如刚才的这些工作场景,很或然最终写起来是其一样子:

<Employee-Panel>
    <Employee-List></Employee-List>
    <Employee-Form></Employee-Form>
</Employee-Panel>

代码laycode –
v1.1

对此UI层,最好的组件化方式是标签化,比如下面代码中就是多个标签表明了整套界面。但自我个人坚决不予滥用标签,并不是把各类东西都尽量封装就一定好。

全标签化的标题关键有那些:

率先,语义化代价太大。只要用了标签,就自然要求给它适用的语义,约等于命名。但实际用的时候,很大概只是为着把一堆html简化弹指间而已,到底简化出来的那东西应该叫什么名字,光是起名也费不知多少脑细胞。比如您说雇员管理的表单,那几个表单有heading吗,有footer吗,能折叠吗,等等,很难起贰个让外人一看就明白的名字,要么就是特意长。那还算简单的,因为咱们是全组件化,所以很大概会有结合了七种东西的一个较复杂的界面,你想来想去也没办法给它起个名字,于是写了个:

<Panel-With-Department-Panel-On-The-Left-And-Employee-Panel-On-The-Right>
</Panel-With-Department-Panel-On-The-Left-And-Employee-Panel-On-The-Right>

代码laycode –
v1.1

那尼玛……大概我夸张了点,但众多时候项目范围够大,你不起这么复杂的名字,最终很只怕没办法跟作用类似的二个零部件区分开,因为那一个该死的组件都存在于同二个命名空间中。要是仅仅是作为3个界面片段来include,就不存在那种情绪承受了。

比如Angular里面的那种:

<div ng-include="'aaa/bbb/ccc.html'"></div>

代码laycode –
v1.1

就不给它怎么名字,直接include进来,用文件路径来差异。这一个某个的意义可以用其目录结构描述,也等于透过物理名而非逻辑名来标识,目录层次充当了3个很好的命名空间。

近期的一部分主流MVVM框架,比如knockout,angular,avalon,vue等等,都有一种“界面模板”,但这种模板并不只是模板,而是可以算得一种配备文件。某一块界面模板描述了本人与数据模型的关系,当它被解析之后,依据内部的各个设置,与数据建立关联,并且反过来再立异本人所对应的视图。

不含业务逻辑的UI(大概是事情逻辑已分手的UI)基本不符合当作组件来对待,因为就是在逻辑不变的地方下,界面改版的只怕性也太多了。比如尽管是换了新的CSS完成格局,从float布局改成flex布局,都有恐怕把DOM结构少套几层div,由此,在拔取模板的方案中,只好把界面层视为配置文件,无法当做组件,即使这么做,就会轻松很多。

武装行军的时候讲究“逢山开路,遇水搭桥”,那句话的根本在于唯有到有个别地形才开路搭桥,使用MVVM那类形式化解的事体场景,多数时候是一马平川,横着走都得以,不必硬要造路。所以从全部方案看的话,UI层完毕应有是模板与控件并存,大部分地点是模板,少数地点是内需独自花时间搞的路和桥。

其次,配置过于复杂。有那多少个事物其实不太相符封装,不但封装的代价大,使用的代价也会很大。有时候会发现,调用代码的绝大多数都以在写各样配置。

似乎刚刚的雇员表单,既然您不从标签的命名上去区分,那必将会在组件上加配置。比如你本来想那样:

<EmployeeForm heading="雇员表单"></EmployeeForm>

代码laycode –
v1.1

下一场在组件内部,判断有没有设置heading,固然没有就不出示,假如有,就显示。过了二日,产品问能或不能把heading里面的某多少个字加粗只怕换色,然后码农起始容许那一个heading属性传入html。没多短时间之后,你会好奇地觉察有人用你的机件,没跟你说,就在heading里面传出了折叠按钮的html,并且用拔取器给折叠按钮加了轩然大波,点一下自此仍可以折叠这几个表单了……

然后您一想,这几个可怜,小编得给她再加个配置,让她能很简短地操纵折叠按钮的体现,可是今后那样写太不直观,于是利用对象社团的布局:

<EmployeeForm>
    <Option collapsible="true">
        <Heading>
            <h4><strong>雇员</strong>表单</h4>
        </Heading>
    </Option>
</EmployeeForm>

代码laycode –
v1.1

然后又有一天,发现有不胜枚举面板都可以折叠,然后特意创立了贰个可折叠面板组件,再创建了一种持续机制,其余普通工作面板从它两次三番,从此一发不可收拾。

本人举那例子的意趣是为了印证什么吗,我想说,在规模较大的项目中,企图用全标签化加配置的点子来叙述全体的家常工作界面,是毫无疑问事倍功半的,并且那么些范畴越大就越坑,那也多亏ExtJS那类对UI层封装过度的连串存在的最大题材。

其一标题讨论完了,我们来探视别的3个难题:即使UI组件有事情逻辑,应该如何处理。

譬如,性别选用的下拉框,它是贰个格外通用化的功能,照理说是很适合被作为组件来提供的。然而到底什么样封装它,我们就多少讨厌了。这些组件里除了界面,还有多少,那个数据应当内置在组件里吧?理论上从组件的封装性来说,是都应该在中间的,于是就这么造了二个组件:

<GenderSelect></GenderSelect>

代码laycode –
v1.1

其一组件万分美好,只需直接放在任意的界面中,就能显得带有性别数据的下拉框了。性其他数额很当然地是坐落组件的兑现内部,七个写死的数组中。那些太简单了,我们改一下,改成商品销售的国度下拉框。

外部上看,那些没什么不一致,但大家有个需求,本公司商品销售的国家的信息是统一布置的,相当于说,这一个数据出自服务端。那时候,你是还是不是想把二个http请求封装到那组件里?

诸如此类做也不是不可以,但存在至少七个难点:

一旦这类组件在同1个界面中冒出反复,就大概存在请求的浪费,因为有贰个零部件实例就会发出二个请求。
假设国家消息的配备界面与那一个组件同时设有,当我们在计划界面中新增二个国家了,下拉框组件中的数据并不会实时刷新。
第七个难点只是能源的浪费,第2个就是数额的不雷同了。曾经在很多种类中,大家都以手动刷新当前页面来消除那难题的,但到了这一个时代,人们都以追求体验的,在一个全组件化的化解方案中,不应再冒出此类题材。

什么化解那样的问题吗?那就是引入一层Store的概念,每一个组件不间接去到服务端请求数据,而是到相应的前端数据缓存中去获取数据,让那么些缓存自身去跟服务端保持同步。

之所以,在骨子里做方案的经过中,不管是基于Angular,React,Polymer,最终一定都做出一层Store了,不然会有为数不少题材。

 (3)ToString方法有Object提供,使得全体的项目均可以接纳Console.WriteLine()方法

5. 怎么MVVM是一种很好的挑选

大家回想一下刚刚十二分下拉框的组件,发现存在多少个难点:

界面不佳调整。刚才的十分例子相对不难,如若大家是二个省市县三级联动的零件,就相比费心了。比如说,大家想要把水平布局改成垂直的,又大概,想要把高中级的label的字改改,都会相当麻烦。依据传统的做组件的主意,就要加若干配置项,然后组件里面去分别判断,修改DOM结构。
假使数据的发源不是静态json,而是有些动态的劳动接口,那用起来就很艰辛。
大家更加多地须求工作逻辑的复用和纯“控件”的复用,至于那多少个绑定业务的界面组件,复用性其实很弱。
所以,从这个角度,会尽恐怕期望在HTML界面层与javascript业务逻辑之间,存在一种分离。

那儿,再看看绝一大半界面组件存在什么样难点:

偶尔大家考虑一下DOM操作的档次,会意识实际上是很不难枚举的:

1 创建并插入节点
2 移除节点
3 节点的交换
4 属性的设置

代码laycode –
v1.1

大部界面组件封装的两头情节不过是这么些事物的再度。那几个事物,其实是足以因此有些配置描述出来的,比如说,有个别数组以怎么样格局渲染成一个select可能无系列表之类,当数组变动,那么些事物也随即变动,这几个都应有被活动处理,假若某些方案在于今那一个时期还手动操作那么些,这真的是一种落伍。

之所以咱们得以看来,以Angular,Knockout,Vue,Avalon为代表的框架们在这上面做了广大事,固然观点有所出入,但大方向都十分一致,也等于把一大半命令式的DOM操作进度简化为局部配备。

有了那种艺术未来,大家可以追求区别层级的复用:

事务模型因为是纯逻辑,所以极度简单复用
视图模型基本上也是纯逻辑,界面层多数是纯字符串模板,同贰个视图模型搭配差其他界面模板,可以兑现视图模型的复用
同二个界面模板与分歧的视图模型组合,也能直接组合出截然两样的东西
所以这么一来,大家的复用粒度就万分灵活了。正因为这么,作者平素觉得Angular那样的框架战略取向是很正确的,尽管有成百上千战术失误。大家在广大现象下,皆以须要如此的飞速生产手段的。

            class Person

6. 零件的长久积聚

小编们做组件化那件事,一定是一种长时间打算,为了使得当前的成千成万事物可以看作一种积累,在以往还能一连拔取,可能唯有作较小的修改就能使用,所以必须考虑对前途业内的匹配。主要须要考虑的下边有这几点:

尽心尽力中立于言语和框架,使用浏览器的原生性情

1 逻辑层的模块化(ECMAScript module)
2 界面层的元素化(Web Components)

代码laycode –
v1.1

前边有为数不少人对Angular
2.0的激进变更很不认同,但它的改动很大程度上是对专业的一揽子迎合。那不不过它的题材,其实是持有前端框架的标题。不直面这一个难题,不管今后多么好,将来都以死路一条。这么些题材的来自是,那多少个已某些规范约束了模块化和成分歧的推介方式,并且,假使要对现阶段和前途两边做适配的话,基本就无法干了,导致原先的都只可以做一定的搬迁。

模块化的动迁花费还相比小,无论是此前英特尔如故CMD的,都可以依照部分规则转换过来,但组件化的搬迁费用太大了,大致逐个框架都会指出自身的见地,然后有不一样的组件化理念。

要么从八个典型的事物的话:Polymer,React,Angular。

Polymer中的组件化,其实就是标签化。那里的竹签,并不只是界面成分,甚至逻辑组件也可以那样,比如这些代码:

<my-panel>
    <core-ajax id="ajax" url="http://url" params="{{formdata}}" method="post"></core-ajax>
</my-panel>

代码laycode –
v1.1

只顾到此处的core-ajax标签,很肯定那早就是纯逻辑的了,在一大半前端框架恐怕库中,调用ajax肯定不是如此的,但在浏览器端这么干也不是它独创,比如flash里面的WebService,比如早期IE中基于htc达成的webservice.htc等等,都以这么干的。在Polymer中,这类东西叫做非可知成分(non-visual-element)。

React的组件化,跟Polymer略有不一样,它的界面部分是标签化,但假设有单纯的逻辑,如故纯javascript模块。

既然大家的兑现方式都那么差异,那我们怎么搞出尽可能可复用的零部件呢?难题到结尾依旧要绕到Web
Components上。

在Web Components与前者组件化框架的涉及上,作者以为是这么个规范:

各个前端组件化框架应当尽量以Web
Components为内核,它致力于集体那么些Components与数据模型之间的涉及,而不去关切有个别具体Component的中间贯彻,比如说,2个列表组件,它毕竟内部使用什么已毕,组件化框架其实是不要关切的,它只应当关注那个组件的数额存取接口。

下一场,那么些组件化框架再去依据自个儿的见识,进一步对这几个专业Web
Components举办打包。换句话说,业务开发人士使用有些组件的时候,他是应当感知不到那么些组件内部终归拔取了Web
Components,依旧平昔使用传统艺术。(那点有个别理想化,大概并不是那么不难形成,因为大家还要管理像import之类的事体)(++可是,小编深信不疑将来会成功的!)。

            {

7. 我们需求关爱如何

日前来看,前端框架/库照旧处在混战期,可比中国历史上的春秋寒朝,百家齐放,作为跟随者来说,那是很忧伤的,因为手足无措,很可能您作为八个公司的前端架构师只怕技术COO,需要做一些选型工作,但选哪些能担保几年后不被淘汰呢?基本没有。

虽说大家不知底未来怎么着框架会流行,但大家得以从一些细节方面去关怀,某些具体的下边,将来会有啥样,也得以驾驭一下在有个别具体领域存在什么样的方案。一个完好的框架方案,无非是以下四个地点的总结。

                   public string Name { get; set; }

7.1 模块化

那块照旧不讲了,支付宝seajs还有百度ecomfe那四个团队的人相应都能比作者讲得好得多。

                   public int Age { get; set; }

7.2 Web Components

正文前边议论过局部,也不深刻了。

                   //当写第10个的时候写入上边的不二法门

7.3 变更检测

我们知晓,现代框架的多个特色是自动化,也等于把本来的片段手动操作提取。在前端编程中,最广大的代码是在干什么吧?读写多少和操作DOM。不少现代的框架/库都对那地点作了拍卖,比如说通过某种安顿的办法,由框架自动抬高一些关乎,当数码变动的时候,把DOM举办对应修改,又比如说,当DOM发生改变的时候,也换代对应的数据。

其一涉及进程或许会用到二种技术。首先我们看怎么通晓多少在变更,那其间有二种途径:

                   public override string ToString()

① 、存取器的包裹。那一个的情致约等于对数据开展一层包装,比如:
var data = {
    name: "aaa",
    getName: function() {
        return this.name;
    },
    setName: function(value) {
        this.name = value;
    }
}

代码laycode –
v1.1

那般,不允许用户直接调用data.name,而是调用对应的八个函数。Backbone就是通过这样的体制已毕数据变动观测的,那种方法适用于大约全数浏览器,缺点就是相比困苦,要对各类数据开展打包。

本条机制在稍微新一点的浏览器中,也有别的一种已毕格局,那就是defineProperty相关的有的方法,使用更优雅的存取器,那样外围得以毫不调用函数,而是平素用data.name那样举办质量的读写。

进口框架avalon使用了那么些机制,低版本IE中从未defineProperty,但在低版本IE中不停有javascript,还留存VBScript,那里边有存取器,所以他都行地行使了VBS做了如此1个卓殊封装。

基于存取器的机制还有个费力,就是历次动态添加属性,都必须再添加对应的存取器,否则那天性子的转移就不能赢得。

                   {

二、脏检测。

以Angular
1.x为代表的框架使用了脏检测来获知多少变动,那个机制的光景原理是:

保留数据的新旧值,每当有一对DOM大概网络、定时器之类的事件暴发,用这一个事件之后的数额去跟在此以前封存的多少举办比对,假若一致,就不触发界面刷新,否则就刷新。

以此办法的理念是,控制全部只怕造成数据变动的起点(相当于各样风云),在她们大概对数据进行操作之后,判断新旧数据是还是不是有浮动,忽略全数中等变更,相当于说,若是你在同贰个事变中,把某部数据任意修改了诸数十二次,但最后改回来了,框架会以为你怎么着都没干,也就不会打招呼界面去刷新了。

不可不可以认的是,脏检测的作用是比较低的,主假若无法准确获知多少变动的熏陶,所以当数据量更大的景况下,浪费更严重,必要手动作一些优化。比如说多少个很大的数组,生成了3个界面上的列表,当有个别项选中的时候,改变颜色。在这种机制下,每一遍变更那一个项的数额状态,就需求把具备的项都跟原先相比五回,然后,还要再全体相比较一回发现并未涉嫌引起的浮动了,才能对应刷新界面。

                          return Name;

③ 、观望机制。

在ES7里面,引入了Object的observe方法,可以用来监控指标或数组的改变。

这是近日停止最入情入理的洞察方案。这几个机制很纯粹高效,比如说,上等兵跟战士说,你去旁观对面那二个碉堡里面的情况。那一个意思很复杂,包括怎么样吗?

1 是不是加人了
2 是不是有人离开了
3 谁跟谁换岗了
4 上面的旗子从太阳旗换成青天白日了

代码laycode –
v1.1

所谓观看机制,也等于考察对象属性的更改,数组成分的骤增,移除,地方变动等等。大家先考虑一下界面和数据的绑定,那本来就应该是3个表面的观看,你是数码,小编是界面,你点头小编微笑,你伸手小编打人。那种绑定本来就应有是个松散关系,不应该因为要绑定,须要破坏原有的一对事物,所以很肯定更客观。

除外数量的改观能够被观看,DOM也是足以的。不过当前大部分双向同步框架都以通过事件的办法把DOM变更同步到数量上。比如说,有个别文本框绑定了一个对象的习性,这很或许,框架之中是监控了那一个文本框的键盘输入、粘贴等相关事件,然后取值去往对象里写。

这么做可以缓解一大半难题,可是即使您平素myInput.value=”111”,这个改变就无可如何获取了。这么些不算大难题,因为在1个双向绑定框架中,2个既被监督,又手工赋值的东西,自己也正如怪,可是也有局部框架会尝试从HTMLInputELement的原型上去覆盖value赋值,尝试把那种东西也纳入框架管辖范围。

其它3个标题,那就是我们只考虑了特定元素的特定属性,可以经过事件得到变更,怎么样拿到更广泛意义上的DOM变更?比如说,一般属性的更改,只怕甚至子节点的增删?

DOM4引入了MutationObserver,用于落实那种变动的洞察。在DOM和数码里面,是不是需求如此复杂的观赛与共同机制,近年来尚无定论,但在全体前端开发逐步自动化的大趋势下,那也是一种值得尝试的事物。

复杂的涉嫌监控不难造成预期之外的结果:

1 慕容复要复国,每天读书练武,各种谋划
2 王语嫣观察到了这种现象,认为表哥不爱自己了
3 段誉看到神仙姐姐闷闷不乐,每天也茶饭不思
4 镇南王妃心疼爱子,到处调查这件事的原委,意外发现段正淳还跟旧爱有联系
5 ……
6 总之这么下来,最后影响到哪里了都不知道,谁让丘处机路过牛家村呢?

代码laycode –
v1.1

因此,变更的涉嫌监控是很复杂的二个连串,特别是其中产生了闭环的时候。搭建整个这么一套东西,需要卓殊精密的安排,否则精晓整个机制的人一旦用特定情景轻轻一推就倒了。灵智上人固然武术过人,接连碰到欧阳锋,周伯通,黄药师,全体都是上来就平素被抓了后颈要害,大约就是这意味。

polymer达成了二个observe-js,用于观望数组、对象和途径的改观,有趣味的可以关怀。

在有点框架,比如aurelia中,是叶影参差使用了存取器和考察情势,把存取器作为观看方式的降级方案,在浏览器不扶助observe的情景下利用。值得一提的是,在脏检测方法中,变更是统一后批量交到的,那点日常被其余三种方案的使用者忽视。其实,即利用此外二种办法,也依然须要贰个合并与批量提交进程。

怎么通晓那些事情吗?数据的绑定,最后都是要反映到界面上的,对于界面来说,其实只关切你每回操作所带来的多少变动的一直,并不须要关切中间进程。比如说,你写了那般二个巡回,放在某些按钮的点击中:

for (var i=0; i<10000; i++) {
    obj.a += 1;
}

代码laycode –
v1.1

界面有一个东西绑定到这些a,对框架来说,相对不应有把高中级经过一向运用到界面上,以刚才这么些事例来说,合理的气象只应当存在两次对界面DOM的赋值,那些值就是对obj.a举行了一千0次赋值之后的值。即使用存取器大概旁观形式,发现了对obj上a属性的那10000次赋值进程,这一个赋值仍然都不可以不被放弃,否则就是很可怕的荒废。

React使用虚拟DOM来减弱中间的DOM操作浪费,本质跟这些是一律的,界面只应当响应逻辑变更的竣事状态,不应有响应中间状态。这样,如若有一个ul,其中的li绑定到三个一千成分的数组,当第二回把那一个数组绑定到这些ul上的时候,框架之中也是可以优化成一次DOM写入的,类似事先常用的那种DocumentFragment,可能是innerHTML一遍写入整个字符串。在这几个上边,全体优化出色的框架,内部贯彻机制都应该类似,在那种方案下,是不是使用虚拟DOM,对质量的震慑都以很小的。

                   }

7.4 Immutable Data

Immutable
Data是函数式编程中的3个概念,在前端组件化框架中能起到部分很奇异的意义。

它的大约理念是,任何一种赋值,都应该被转化成复制,不设有指向同1个地点的引用。比如说:

var a = 1;
var b = a;
b = 2;

console.log(a==b);

代码laycode –
v1.1

本条我们都知道,b跟a的内存地址是不同的,不难类型的赋值会进展复制,所以a跟b不对等。但是:

var a = {
    counter : 1
};
var b = a;

b.counter++;
console.log(a.counter==b.counter);

代码laycode –
v1.1

那时候因为a和b指向同一的内存地址,所以若是修改了b的counter,a里面的counter也会随之变。

Immutable
Data的看法是,小编能不可能在那种赋值景况下,间接把本来的a完全复制一份给b,然后将来大家各自变各自的,相互不影响。光凭这么一句话,看不出它的用处,看例子:

对此全组件化的连串,不可幸免会现出过多嵌套的机件。嵌套组件是一个很困难的题材,在广大时候,是不太好处理的。嵌套组件所存在的难点至关主要在于生命周期的治本和数量的共享,很多已有方案的上下级组件之间都是存在多少共享的,但假设前后层存在共享数据,那么就会损坏组件的独立性,比如下边的贰个列表控件:

<my-list list-data="{arr}">
    <my-listitem></my-listitem>
    <my-listitem></my-listitem>
    <my-listitem></my-listitem>
</my-list>

代码laycode –
v1.1

小编们在赋值的时候,一般是在外层全部赋值三个接近数组的数额,而不是友善挨个在各样列表项上赋值,不然就很费力。可是只要前后层持有相同的引用,对组件的封装性很不利于。

例如在刚刚以此例子里,假使数据源如下:

var arr = [
    {name: "Item1"}, 
    {name: "Item2"}, 
    {name: "Item3"}
];

代码laycode –
v1.1

透过类似那样的法子赋值给界面组件,并且由它在中间给各样子组件分别开展多少项的赋值:

list.data = arr;

代码laycode –
v1.1

赋值之后会有哪些的结果吗?

console.log(list.data == arr);
console.log(listitem0.data == arr[0]);
console.log(listitem1.data == arr[1]);
console.log(listitem2.data == arr[2]);

代码laycode –
v1.1

那种方案里面,前边那2个log输出的结果都会是true,意思就是内层组件与外层共享数据,一旦内层组件对数据开展更改,外层中的也就改变了,那鲜明是违背组件的封装性的。

之所以,有一部分方案会引入Immutable
Data的定义。在这几个方案里,内外层组件的数据是不共享的,它们的引用差异,每一个组件实际上是怀有了团结的数码,然后引入了电动的赋值机制。

此时再看看刚才尤其例子,就会发觉两层的义务很清楚:

外层持有3个近乎数组的东西arr,用于形成全体列表,但并不关心每条记下的底细
内层持有某条记下,用于渲染列表项的界面
在全方位列表的演进经过中,list组件依照arr的多寡长度,实例化若干个listitem,并且把arr中的各条数据赋值给相应的listitem,而那一个赋值,就是immutable
data起成效的地点,其实是把那条数据复制了一份给其中,而不是把外围那条记下的引用赋值进去。内层组件发现自身的多少变动现在,就去进行对应的渲染
假使arr的条数变更了,外层监控那几个数额,并且根据变更类型,添加或然去除某些列表项
假诺从外面改变了arr中某一条记下的内容,外层组件并不直接处理,而是给相应的内层进行了两遍赋值
倘诺列表项中的有些操作,改变了自身的值,它首先是把自身全体的数量举行转移,然后,再经过immutable
data把数量往外合办一份,那样,外层组件中的数据也就更新了。
所以大家再看这么些历程,真是要命清晰明了,而且内外层各司其职,互不干涉。那是分外便于大家制作一个全组件化的大型Web应用的。各级组件之间存在相比较松散的联系,而各种组件的里边则是查封的,那正是大家所急需的结果。

说到此地,须要再提一个不难混淆的东西,比如下面那几个例子:

<outer-component>
    <inner-component></inner-component>
</outer-component>

代码laycode –
v1.1

如若大家为了给inner-component做一些体裁定位之类的作业,很大概在上下层组件之间再加一些外加的布局元素,比如变成那样:

<outer-component>
    <div>
        <inner-component></inner-component>
    </div>
</outer-component>

代码laycode –
v1.1

那边中间多了超级div,也可能是多少级成分。即使有用过Angular
1.x的,只怕会清楚,若是这之中硬造一流效率域,搞个ng-if之类,就可能存在一连串功效域的赋值难点。在上头那些事例里,若是在最外层赋值,数据就会是outer
-> div ->
inner那样,那么,从框架设计的角度,这两遍赋值都应有是immutable的呢?

不是,第6次赋值是非immutable,第二回才需如若,immutable赋值应当仅存在于组件边界上,在组件内部不是专门有须要运用。刚才的例证里,依附于div的那层变量应当如故跟outer组件在同一层面,都属于outer组件的人民内部争辨。

这里是facebook实现的immutable-js库

            }

7.5 Promise与异步

前端一般都习惯于用事件的办法处理异步,但众多时候纯逻辑的“串行化”场景下,那种措施会让逻辑很难阅读。在新的ES规范里,也有yield为表示的种种原生异步处理方案,可是那一个方案依旧有很大的明亮障碍,流行度有限,很大程度上会一贯滞留在基础较好的开发人士手中。越发是在浏览器端,它的受众应该会比node里面还要狭窄。

前者里面,处理延续异步消息的最能被大规模接受的方案是promise,作者那边并不琢磨它的原理,也不研讨它在业务中的使用,而是要提一下它在组件化框架之中所能起到的功用。

如今已经没有哪个前端组件化框架可以不考虑异步加载难点了,因为,在前者那几个圈子,加载就是2个绕不过去的坎,必须有了加载,才能有履行进度。各个组件化框架都不能拦截本人的使用者规模膨胀,因而也应有在框架层面提议消除方案。

小编们只怕会动态配置路由,也可能在动态加载的路由中又引入新的机件,怎样控制这几个东西的生命周期,值得仔细推敲,若是在框架层面全异步化,对于编程体验的一致性是有益处的。将各项接口都promise化,可以在可维护性和可扩充性上提供较多造福。

我们在此以前大概熟稔XMLHTTP那样的通讯接口,那么些事物即使被广为使用,不过在优雅性等地点,存在有的标题,所以方今出来了代表方案,那就是fetch。

细节可以瞻仰月影翻译的那篇【翻译】那几个API很“迷人”——(新的Fetch API)

在不资助的浏览器上,也有github完结的二个polyfill,即便不全,但足以凑合用window.fetch
polyfill

世家可以看出,fetch的接口就是基于promise的,那应当是前端开发人士最简单接受的方案了。

            class Program

7.5 Isomorphic javascript

其一东西的意思是上下端同构的javascript,约等于说,比如一块界面,可以拔取在前者渲染,也得以采纳在后端渲染,值得关怀,可以缓解像seo之类的题材,但近年来还无法处理很复杂的情景,持续关心呢。

            {

8. 小结

很谢谢能收看此间,以上这几个是作者近一年的部分盘揣度算。从技术选型的角度看,做大型Web应用的人会很痛楚,因为那是一个不足的年份,近来已有的具备框架/库都存在差异水平的缺点。当你向未来看去,发现它们都以索要被扬弃,恐怕被改建的,人最惨痛的是在知晓许多东西不佳,却又要从中挑选1个来用。@严清
跟@寸志
@题叶研商过那几个难题,认为以后那些等级的技巧选型难做,不如等一阵,我一心赞同他们的视角。

选型是难,不过从上学的角度,可真的是挺好的权且,能学的东西太多了,作者每日路上都在尽力看有或然值得看的东西,可依然看不完,只可以全力去跟上一代的脚步。
(++前端技术迭代的进度越来越快,技术不断在摇摆,对长远的品种拥有严峻的考验。在没有很好的出路前对大型项目标共同体风险都不便把控。)

以下一段,与诸位共勉:

It was the best of times, it was the worst of times, it was the age of
wisdom, it was the age of foolishness, it was the epoch of belief, it
was the epoch of incredulity, it was the season of Light, it was the
season of Darkness, it was the spring of hope, it was the winter of
despair, we had everything before us, we had nothing before us, we were
all going direct to Heaven, we were all going direct the other way–in
short, the period was so far like the present period, that some of its
noisiest authorities insisted on its being received, for good or for
evil, in the superlative degree of comparison only.

 

                   static void Main(string[] args)

                   {

                          int[] nums = { 1, 34, 4, 65, 7, 87, 454 };

                          Console.WriteLine(nums);

                          //输出:System.Int32[]

                          //准备对象

                          Person p = new Person();

                          p.Name = “韩迎龙”;

                          p.Age = 19;

                          Console.WriteLine(p);

                          //输出:智能机器.Person

                          //第三个

                          Person p1 = new Person();

                          p1.Name = “韩迎龙”;

                          p1.Age = 19;

                          Console.WriteLine(p);

                          //输出张三

                          Console.ReadKey();

                   }

            }

 (4)多态的维持

            1)继承,相同名字的不二法门(重载不算)

            2)里氏转换原则

 (5)is和as

            1)判断父类继承

            2)判断接口达成

            3)判断拆箱和装箱

  2.多态完结计算器

 (1) 新建一个控制台应用程序,起名为多态计算器

 (2)添加一个CalculstingWay类,表示计算的方法

            /// <summary>

            /// 计算机的计算

            /// </summary>

            class CalculstingWay

            {

                   int num1;

                   int num2;

                   public int Num1

                   {

                          get { return num1; }

                          set { num1 = value; }

                   }

                   public int Num2

                   {

                          get { return num2; }

                          set { num2 = value; }

                   }

                   public CalculstingWay(int n1, int n2)

                   {

                          num1 = n1;

                          num2 = n2;

                   }

                   public virtual int Calculating()

                   {

                          //这个方法是需要子类重写的

                          return 0;

                   }

            }

(3)添加一个Add类,表示实现加法的计算

         /// <summary>

            /// 提供加法计算的方法

            /// </summary>

            class Add:CalculstingWay

            {

                   public Add(int n1, int n2)

                          : base(n1, n2)

                   {

                   }

                   public override int Calculating()

                   {

                          return base.Num1 + base.Num2;

                   }

            }    

     (4)添加一个Sub类,表示实现减法的计算

         /// <summary>

            /// 提供减法计算的方法

            /// </summary>

            class Sub : CalculstingWay

            {

                   public Sub(int n1, int n2)

                          : base(n1, n2)

                   {

                   }

                   public override int Calculating()

                   {

                          return base.Num1 - base.Num2;

                   }

            }    

(5)添加一个Multi类,表示实现乘法的计算

         /// <summary>

            /// 提供乘法计算的方法

            /// </summary>

            class Multi : CalculstingWay

            {

                   public Multi(int n1, int n2)

                          : base(n1, n2)

                   {

                   }

                   public override int Calculating()

                   {

                          return base.Num1 + base.Num2;

                   }

            }    

(6)添加一个Div类,表示实现除法的计算

         /// <summary>

            /// 提供除法计算的方法

            /// </summary>

            class Div : CalculstingWay

            {

                   public Div(int n1, int n2)

                          : base(n1, n2)

                   {

                   }

                   public override int Calculating()

                   {

                          return base.Num1 + base.Num2;

                   }

            }

 (7)添加一个Calculator类,表示计算器类

            /// <summary>

            /// 表示计算器

            /// </summary>

            class Calculator

            {

                   //可以进行计算的对象

                   CalculstingWay cal;

                   public Calculator(int num1, int num2, string oper)

                   {

                          switch (oper)

                          {

                                 case "+":

                                        cal = new Add(num1, num2);

                                        break;

                                 case "-":

                                        cal = new Sub(num1, num2);

                                        break;

                                 case "*":

                                        cal = new Multi(num1, num2);

                                        break;

                                 case "/":

                                        cal = new Div(num1, num2);

                                        break;

                                 default:

                                        cal = null;

                                        break;

                          }

                   }

                   public int jisuan()

                   {

                          if (cal != null)

                          {

                                 return cal.Calculating();

                          }

                          else

                          {

                                 return -1;

                          }

                   }

            }

  3. 虚无方法

 (1) 父类提供1个可以被重写的主意,有子类重写,通过父类,new子类来调用

 (2)父类不要求方法体

 (3)语法:[public] abstract 重临类型 方法名(参数);

                   和措施相比有以下几点需求小心的:

                   1)去掉方法体,直接在圆括号为止的时候加分号

                   2)加上abstract进行修饰

 (4)抽象方法只允许在抽象类中存在

            1)只要在class关键字前边用abstract修饰即可

                   abstract class 类名

                   {

                          //成员

                   }

(5)抽象方法,抽象类就是为着被子类继承,重写的

   abstract class Animal

            {

                   public abstract void Shout();

            }

            class Dog : Animal

            {

                   public override void Shout()

                   {

                          Console.WriteLine("财旺福王运道旺");

                   }

            }

            class Cat : Animal

            {

                   public override void Shout()

                   {

                          Console.WriteLine("喵喵喵");

                   }

            }

            class Program

            {

                   static void Main(string[] args)

                   {

                          Animal[] animals = {

                                                                new Dog(),

                                                              new Cat() 

                                                         };

                          for (int i = 0; i < animals.Length; i++)

                          {

                                 animals[i].Shout();

                          }

                          Console.ReadKey();

                   }

            }    

 (6)抽象方法的底细

            1)抽象类中得以包涵哪些事物?

                   ->比一般类多了充饥画饼成员

                   ->抽象成员有有如何:方法,属性,索引器,事件声明

            2)抽象类不允许实例化,不大概new

            3)抽象类可以有构造方法

            4)抽象类可以来源于非抽象类

                   class MyBase

                   {

                   }

                   abstract class Test : MyBase

                   {

                          public abstract void Func();

                   }

                   class MySub : Test

                   {

                          public override void Func()

                          {

                                
Console.WriteLine(“抽象类可以来源于非抽象类”);

                          }

                   }

            5)抽象类必须被子类重写,除非子类也是空虚的

 (7)陶冶:有贰个形态Shape类,派生出圆Circle,矩形Rectangle和椭圆形Square,分别计算他们的面积Area和周长Perimeter 

   1)新建一个控制台项目:起名为多态小案例

   2)添加一个Shape类,实现计算面积和周长的方法

                   abstract class Shape

                   {

                          public abstract double GetArea();

                          public abstract double GetPerimeter();

                   }

   3)添加一个Circle类,实现计算圆的面积和周长

                   class Circle : Shape

                   {

                          int r;

                          public Circle(int r)

                          {

                                 this.r = r;

                          }

                          public override double GetArea()

                          {

                                 return Math.PI * Math.Pow(r, 2);

                          }

                          public override double GetPerimeter()

                          {

                                 return 2 * Math.PI * r;

                          }

                   }

  4)添加一个类,实现计算矩形的面积和周长

                   class Rectangle : Shape

                   {

                          double widthX;

                          double heightY;

                          public Rectangle(double widthX, double heightY)

                          {

                                 this.widthX = widthX;

                                 this.heightY = heightY;

                          }

                          public override double GetArea()

                          {

                                 return widthX * heightY;

                          }

                          public override double GetPerimeter()

                          {

                                 return 2 * (widthX + heightY);

                          }

                   }

  5)添加一个类,实现计算正方形的面积和周长

                   class Square : Shape

                   {

                          double length;

                          public Square(double length)

                          {

                                 this.length = length;

                          }

                          public override double GetArea()

                          {

                                 return Math.Pow(length, 2);

                          }

                          public override double GetPerimeter()

                          {

                                 return 4 * length;

                          }

                   }

                   class Square1 : Rectangle

                   {

                          public Square1(double length)

                                 : base(length, length)

                          {

                          }

                   }

  6)在Main方法中实现的代码如下:

                   class Program

                   {

                          static void Main(string[] args)

                          {

                                 Circle circle = new Circle(5);

                                 Console.WriteLine(circle.GetArea().ToString("0.00"));

                                 Console.WriteLine(circle.GetPerimeter().ToString("0.00"));

                                 Rectangle rec = new Rectangle(5, 10);

                                 Console.WriteLine(rec.GetArea());

                                 Console.WriteLine(rec.GetPerimeter());

                                 Square square = new Square(5);

                                 Console.WriteLine(square.GetArea());

                                 Console.WriteLine(square.GetPerimeter());

                                 Square1 sqr = new Square1(5);

                                 Console.WriteLine(sqr.GetArea());

                                 Console.WriteLine(sqr.GetPerimeter());

                          }

                   }

 (8)抽象属性

            1)使用abstract修饰

            2)去掉方法体

            3)语法:public abstract 再次回到类型 属性

                          {

                                 get;

                                 set;

                          }

            4)自动属性必须包涵get,set方法

            5)抽象属性可以定义只读,只写,

 (9)由子类已毕抽象属性的艺术

            1)用override重写属性

            2)添加三个字段,使用品质

  1. 面向对象计算器(简单工厂总括器)

    (1) 新建二个控制台应用程序,起名为:不难工厂总括器(最好写成英文的,小编是为着学习直接写成汉语的了)

    (2)新建三个CalculatingWay类,完毕计算机的父类总结

             /// <summary>
    
            /// 计算机的计算
    
            /// </summary>
    
            abstract class CalculstingWay
    
            {
    
                   int num1;
    
                   int num2;
    
                   public int Num1
    
                   {
    
                          get { return num1; }
    
                          set { num1 = value; }
    
                   }
    
                   public int Num2
    
                   {
    
                          get { return num2; }
    
                          set { num2 = value; }
    
                   }
    
                   public CalculstingWay(int n1, int n2)
    
                   {
    
                          num1 = n1;
    
                          num2 = n2;
    
                   }
    
                   public abstract int Calculating();
    
            }
    

    (3)新建1个Add类,

            /// <summary>
    
            /// 提供加法计算的方法
    
            /// </summary>
    
            class Add:CalculstingWay
    
            {
    
                   public Add(int n1, int n2)
    
                          : base(n1, n2)
    
                   {
    
                   }
    
                   public override int Calculating()
    
                   {
    
                          return base.Num1 + base.Num2;
    
                   }
    
            }
    

    (4)新建贰个Sub类,

            /// <summary>
    
            /// 提供减法计算的方法
    
            /// </summary>
    
            class Sub : CalculstingWay
    
            {
    
                   public Sub(int n1, int n2)
    
                          : base(n1, n2)
    
                   {
    
                   }
    
                   public override int Calculating()
    
                   {
    
                          return base.Num1 - base.Num2;
    
                   }
    
            }
    

    (5)新建三个Multi类,

         /// <summary>
    
            /// 提供乘法计算的方法
    
            /// </summary>
    
            class Multi : CalculstingWay
    
            {
    
                   public Multi(int n1, int n2)
    
                          : base(n1, n2)
    
                   {
    
                   }
    
                   public override int Calculating()
    
                   {
    
                          return base.Num1 + base.Num2;
    
                   }
    
            }    
    

    (6)新建壹个Div类,

         /// <summary>
    
            /// 提供除法计算的方法
    
            /// </summary>
    
            class Div : CalculstingWay
    
            {
    
                   public Div(int n1, int n2)
    
                          : base(n1, n2)
    
                   {
    
                   }
    
                   public override int Calculating()
    
                   {
    
                          return base.Num1 + base.Num2;
    
                   }
    
            }    
    

    (7)新建二个Factory类

            static class Factory
    
            {
    
                   public static CalculstingWay GetCalculator(int n1,int n2,string oper)
    
                   {
    
                          switch (oper)
    
                          {
    
                                 case "+":
    
                                        return new Add(n1, n2);
    
                                 case "-":
    
                                        return new Sub(n1, n2);
    
                                 case "*":
    
                                        return new Multi(n1, n2);
    
                                 case "/":
    
                                        return new Div(n1, n2);
    
                                 default:
    
                                        return null;
    
                          }
    
                   }
    
            }    
    

    (8)在Main方法中写入如下那段代码:

            class Program
    
            {
    
                   static void Main(string[] args)
    
                   {
    
                          //提示用户输入
    
                          Console.Write("请用户输入第一个数字:");
    
                          int num1 = GetInputNum();
    
                          Console.Write("请用户输入第一个数字:");
    
                          int num2 = GetInputNum();
    
                          Console.Write("请输入运算符");
    
                          string oper = Console.ReadLine();
    
                          //开始生产
    
                          CalculstingWay cal = Factory.GetCalculator(num1, num2, oper);
    
                          //开始投入使用
    
                          if (cal != null)
    
                          {
    
                                 int res = cal.Calculating();
    
                                 Console.WriteLine("{0}{1}{2}={3}", num1, oper, num2, res);
    
                          }
    
                          else
    
                          {
    
                                 Console.WriteLine("运算符有误");
    
                          }
    
                   }
    
                   public static int GetInputNum()
    
                   {
    
                          return GetInputNum(int.MinValue, int.MaxValue);
    
                   }
    
                   /// <summary>
    
                   /// 完成int类型数据的输入,并返回,要求输入的数字在0到给定的数字之间
    
                   /// </summary>
    
                   /// <param name="max">给定的数字的上限</param>
    
                   /// <returns></returns>
    
                   public static int GetInputNum(int max)
    
                   {
    
                          return GetInputNum(0, max);
    
                   }
    
                   /// <summary>
    
                   /// 完成int数字的输入,要求在给定范围之间
    
                   /// </summary>
    
                   /// <param name="min">给定范围的下线</param>
    
                   /// <param name="max">给定范围的上线</param>
    
                   /// <returns></returns>
    
                   public static int GetInputNum(int min, int max)
    
                   {
    
                          string str = Console.ReadLine();
    
                          int num;
    
                          while (true)
    
                          {
    
                                 try
    
                                 {
    
                                        num = Convert.ToInt32(str);
    
                                        if (num > min && num < max)
    
                                        {
    
                                               break;
    
                                        }
    
                                        Console.Write("输入数字不再{0}到{1}之间,请重新输入", min, max);
    
                                        str = Console.ReadLine();
    
                                 }
    
                                 catch
    
                                 {
    
                                        Console.Write("输入有误,请重新输入");
    
                                        str = Console.ReadLine();
    
                                 }
    
                          }
    
                          return num;
    
                   }
    
            } 
    

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图