起名C#基础系列第五首

序言:
完全是自个儿以攻过程遭到著录的记,只不过分享一下吃不少恰恰起学习.net编程的食指会快的学会C#语言

1. 胡组件化这么难开

Web用的组件化是一个充分复杂的话题。

于大型软件中,组件化是同一种植共识,它一面提高了出效率,另一方面降低了维护成本。但是在Web前端这个领域,并没有异常通用的组件模式,因为缺一个大家都能认同的落实方式,所以多框架/库都落实了和睦之组件化方式。

前端圈最爱让之轮子了,没有孰别的领域会冒出这么烂而蓬勃的面貌。这一面说明前端领域的创造力很旺盛,另一方面却证实了根基设备是休完美的。

自曾有了这么一个类比,说明某种编程技术及其生态发展之几只级次:

首的时节人们应接不暇在补全各种API,代表在她们有所的东西还不行匮乏,需要在语言和基础设备达到承到
然后即便开始各种模式,标志他们做的事物逐渐变充分转移复杂,需要再行好的集团了
然后就是各项分层MVC,MVP,MVVM,(++MV*)之类,可视化开发,自动化测试,团队共同网等等,说明重视生产效率了,也便是所谓工程化
那么,对比就三单等级,看看关注这三种东西的食指,觉得Web发展及啊一样步了?

细节的话,大概是模块化和组件化标准将大规模落地(好坏先不论),各类API也大概齐备了,终于见到起飞的巴了,各种框架几年内会发坏强力的洗牌,如果不考虑老旧浏览器的关,这个洗牌过程将大大加快,然后才能够释放Web前端的产能。

可咱不能不小心到,现在这些将普及的科班,很多且见面叫前面的办事带来改变。用工业系统的发展史来比,前端领域时正处在蒸汽机发明之前,早期机械(比如《木兰辞》里面的机杼,主要是动力和资料比较老)已经推广之这样一个品级。

所以,从之角度看,很多框架/库是碰头消亡的(专门举行模块化的AMD和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的准,主要影响之凡有的AMD/CMD的加载与有关管理网,从之角度来拘禁,正而seajs团队的@afc163
所说,不管是AMD还是CMD,都过时了。

模块化相对来说,迁移还比好,基本只有是彻头彻尾逻辑的包裹,跟AMD或者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. 立即最为新颖的前端组件化框架/库

以2015年初是时空接触看,前端领域有三独框架/库引领时尚,那就算是Angular,Polymer,React(排名按首字母),在知乎的当即篇2014
年末起安比较火的 Web
开发技术?里,我大体回答了一些碰,其他几各情人的答案也不行值得看。关于这三者的细节解析,侯振宇的即篇讲话得杀好:2015面前端框架何去何从

咱们好观看,Polymer这个东西在马上面是产生天然优势的,因为她的核心理念就是依据Web
Components的,也就是说,它基本没有考虑如何化解当前底问题,直接为未来吧发展大方向了。

React的编程模式其实不用专程考虑Web标准,它的迁成本并无算是大,甚至由于其落实机制,屏蔽了UI层实现方式,所以大家能够来看在native上之以,canvas上之以,这还是和基于DOM的编程方式多不同之,所以针对其吧,处理Web
Components的兼容问题要当封门装标签的早晚解决,反正之前为是如包。

Angular
1.x的版,可以说凡是跟同时代的绝大多数框架/库一样,对未来业内的匹配基本没设想,但是又设计后的2.0版对斯产生了无数权,变成了激进变更,突然就改为一个前途之物了。

立三只东旗各有千秋,在可预见的几乎年内以会晤鼎足三分,也许还见面有新的框架出现,能免可知于当下几只流行就难说了。
除此以外,原Angular 2.0底成员Rob
Eisenberg创建了和睦之初一代框架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应用来说,把拥有东西还“组件化”,在管制达会来于生之便利性。我举个例证,同样是编写代码,短代码明显比长代码的可读性更胜,所以众多语言里会提议“一个方式一般不要跨越多少行,一个近似最好永不超过多少行”之类。在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平台上可用。但这种措施啊闹比较累的地方,那就是界面调整比较繁琐。

本文前面有引用侯振宇的那篇稿子里,他提出这些问题:

怎能够拿组件变得更易重用? 具体一点:

自我在用有组件时需重调整一下零件里面元素的各个怎么处置?
我思只要错过丢组件里面有一个因素怎么惩罚? 如何将组件变得重新易扩展? 具体一点:
业务方不断要求被组件加效果怎么惩罚?
为者,还提出了“模板复写”方案,在当下或多或少高达自我出差观点。

咱俩来看望哪把一个业务界面切割成组件。

出如此一个简单易行场景:一个雇员列表界面包括个别单部分,雇员表格和用来填写雇员信息之表单。在这情景下,存在什么样组件?

对此问题,主要设有个别种植倾向,一种植是特把“控件”和比较有通用性的东西封装成组件,另外一种植是任何应用都组件化。

对前一致种植方法吧,这中间仅在多少表格这么一个零部件。
对后一样栽艺术吧,这里面来或是:数据表格,雇员表单,甚至还连雇员列表界面这么一个复老的组件。

随即简单栽方法,就是咱们前面所说之“局部组件化”,“全组件化”。

俺们前提到,全组件化在管理上是存优势的,它可管不同层面的事物都作成类似结构,比如刚之是业务场景,很可能最终写起是者样子:

<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

随即尼玛……可能本身夸张了接触,但众多早晚路规模足够充分,你无自这样复杂的名,最后那个可能没法和功能看似的一个零部件区分开,因为这些该死的机件都留存吃与一个命名空间中。如果单单是作为一个界面片段来include,就无存这种思维负担了。

比如Angular里面的这种:

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

代码laycode –
v1.1

即使无受它们什么名字,直接include进来,用文件路径来区分。这个部分的意向好据此其目录结构描述,也即是通过物理名而非逻辑名来标识,目录层次做了一个杀好的命名空间。

如今底有主流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层封装过度的系在的最好特别问题。

其一题材讨论完毕了,我们来探另外一个问题:如果UI组件有作业逻辑,应该怎么样处理。

像,性别选择的下拉框,它是一个怪通用化的功用,照理说是怪适合为用作组件来提供的。但是到底如何封装它,我们就算聊难了。这个组件里除界面,还产生数量,这些数量应坐在组件里为?理论及于组件的封装性来说,是还应该在里头的,于是便这么过去了一个组件:

<GenderSelect></GenderSelect>

代码laycode –
v1.1

以此组件非常美好,只待直接放在任意的界面被,就能够显示带有性别数据的下拉框了。性别的多寡充分当然地是在组件的落实中,一个状很的数组中。这个极端简单了,我们反一下,改化商品销售的国家下拉框。

标上看,这个没什么区别,但我们发出只要求,本铺商品销售的国度之音是统一配置的,也就是说,这个数目来自服务端。这时候,你是不是思念管一个http请求封装到及时组件里?

然做为不是勿得以,但有至少少独问题:

假如这看似组件在和一个界面被冒出反复,就可能在请求的浪费,因为起一个零部件实例就见面发生一个请。
如果国家信息的布局界面与之组件同时设有,当我们于部署界面被新增一个国家了,下拉框组件中之数码并无见面实时刷新。
第一单问题只是资源的荒废,第二只就是是多少的不平等了。曾经以许多网遭到,大家还是手动刷新时页面来化解当时问题之,但至了是时,人们还是追求体验的,在一个全组件化的化解方案受到,不答应还出现此类问题。

哪化解这样的问题吧?那便是引入一重叠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的激进变更好不认同,但她的更动好十分程度达是针对标准的周全迎合。这不单是它们的题目,其实是所有前端框架的题材。不迎这些题材,不管现在多好,将来犹是死路一久。这个问题之来源于是,这几乎单已经部分规范约束了模块化和元素化的引荐方法,并且,如果如对当下跟未来少边做适配的语,基本就是没学关系了,导致原先的且不得不开肯定的迁移。

模块化的迁成本还比较小,无论是之前AMD还是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的其中贯彻,比如说,一个列表组件,它到底内部采用啊实现,组件化框架其实是不用关心的,它就当关注是组件的数据存取接口。

接下来,这些组件化框架还去因自己之眼光,进一步对这些规范Web
Components进行包装。换句话说,业务开发人员使用某组件的时光,他是应该感知不交此组件内部究竟以了Web
Components,还是一直行使传统艺术。(这一点略带理想化,可能并无是那容易就,因为我们还要管理像import之类的事情)(++但是,我深信不疑以后会形成的!)。

            {

7. 我们得关注什么

即来拘禁,前端框架/库仍然处在混战期,可比中国史及之春秋战国,百小共放,作为跟随者来说,这是坏惨痛之,因为无论是所适从,很可能你当作一个店铺之前端架构师或者技术经理,需要做一些选型工作,但选择谁能管几年后不吃裁呢?基本无。

虽说咱不明白前呀框架会大行其道,但咱得以打有细节方面去关注,某个具体的点,将来会起啊,也可以了解一下每当某个具体领域在什么的方案。一个完全的框架方案,无非是以下多个点的汇总。

                   public string Name { get; set; }

7.1 模块化

这块还是未曰了,支付宝seajs还发生百度ecomfe这半个组织的人应有都能够于自己谈话得好得多。

                   public int Age { get; set; }

7.2 Web Components

正文前面议论过局部,也无透了。

                   //当写第三只之上写副下的法

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做了这样一个郎才女貌封装。

依据存取器的机制还产生个麻烦,就是每次动态添加属性,都得再次续加对应的存取器,否则是特性的更改就无法取。

                   {

二、脏检测。

因为Angular
1.x吧代表的框架下了污染检测来抱知数变动,这个机制的盖原理是:

保存数据的新老值,每当有有DOM或者网络、定时器之类的事件闹,用此事件以后的多少去同之前封存的多寡进行比对,如果同样,就未触发界面刷新,否则即刷新。

这个法子的意见是,控制所有可能引致数据变动的根源(也就是各种风波),在她们唯恐对数据开展操作后,判断新老数据是否有变,忽略所有中变更,也就是说,如果你当与一个波备受,把某部数任意修改了过多次等,但结尾移回去了,框架会以为你啊还并未提到,也便无见面通知界面去刷新了。

不可否认的凡,脏检测的效率是较低的,主要是不可知可靠落知多少变动的影响,所以当数据量更特别的动静下,浪费更重,需要手动作一些优化。比如说一个万分挺之屡屡组,生成了一个界面上的列表,当某个项选中之上,改变颜色。在这种体制下,每次变更之起的数据状态,就待将装有的项都和原来比较相同百分之百,然后,还要更全部较一致坏发现无涉嫌引起的变动了,才会对应刷新界面。

                          return Name;

老三、观察机制。

于ES7里面,引入了Object的observe方法,可以用来监控目标要累组的改观。

就是目前为止最合情合理之观方案。这个机制好准高效,比如说,连长跟战士说,你失去考察对面那个碉堡里面的情况。这个意思甚复杂,包括什么也?

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

代码laycode –
v1.1

所谓观察机制,也就是是相对象属性的更改,数组元素的疯长,移除,位置变动等等。我们先琢磨一下界面和多少的绑定,这自然就活该是一个标的观察,你是数额,我是界面,你点头我微笑,你要我打人。这种绑定本来就应是个松散关系,不应为如果绑定,需要破坏原有的一对物,所以很强烈更合理。

除去数量的更动可以让观察,DOM也是可以的。但是时多数双向共框架还是经波之艺术把DOM变更并到数码上。比如说,某个文本框绑定了一个靶的性,那非常可能,框架内是监督了这文本框的键盘输入、粘贴等有关事件,然后取值去为对象里描写。

这样做可以化解大部分题目,但是倘若您一直myInput.value=”111”,这个改变就没法获取了。这个不算是很题目,因为当一个双向绑定框架中,一个既给监控,又手工赋值的事物,本身吗较老,不过为时有发生有框架会尝试从HTMLInputELement的原型上去覆盖value赋值,尝试将这种东西吗纳入框架管辖范围。

此外一个题材,那就是咱只有考虑了一定元素的特定属性,可以通过波得到反,如何赢得重新普遍意义上的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进行了10000次等赋值之后的价值。尽管用存取器或者相模式,发现了针对性obj上a属性的这10000坏赋值过程,这些赋值还是都必须被放弃,否则即是充分可怕的浪费。

React用虚拟DOM来减少中间的DOM操作浪费,本质和这是同样的,界面只有当应逻辑变更的收尾状态,不应应中间状态。这样,如果来一个ul,其中的li绑定到一个1000首批根本的屡屡组,当首次等将这数组绑定到之ul上的早晚,框架之中也是好优化成一坏DOM写副的,类似事先常用之那种DocumentFragment,或者是innerHTML一次写副满字符串。在此上面,所有优化良好的框架,内部贯彻机制都应有类似,在这种方案下,是否采用虚拟DOM,对性的熏陶都是十分粗的。

                   }

7.4 Immutable Data

Immutable
Data是函数式编程中的一个定义,在前者组件化框架中能于至部分分外奇特的作用。

它的大概理念是,任何一样种植赋值,都当于转接成为复制,不在对同一个地方的援。比如说:

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

这种方案中,后面那几只log输出的结果还见面是true,意思就是是内层组件和外层共享数据,一旦内层组件对数码开展反,外层被之也便改成了,这分明是违背组件的封装性的。

因此,有部分方案会引入Immutable
Data的概念。在这些方案里,内外层组件的数量是免共享的,它们的援不同,每个组件实际上是怀有了协调之数码,然后引入了电动的赋值机制。

此时又望刚才颇例子,就会发觉少层的职责很清楚:

外层持有一个类数组的东西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的吧?

匪是,第一次于赋值是非immutable,第二坏才要是,immutable赋值应当就是吃组件边界及,在组件内部未是特别有必要运用。刚才的事例里,依附于div的那层变量应当还是跟outer组件在同一层面,都属于outer组件的人民内部矛盾。

这里是facebook实现的immutable-js库

            }

7.5 Promise与异步

前者一般都习惯被用事件的措施处理异步,但过多上纯逻辑的“串行化”场景下,这种艺术会为逻辑很为难阅读。在初的ES规范里,也发生yield为代表的各种原生异步处理方案,但是这些方案还是发生特别十分之知道障碍,流行度有限,很充分程度达到会见直接留在基础较好之开发人员手中。尤其是当浏览器端,它的受众应该会于node里面还要小。

前端里面,处理连续异步消息之极致会吃大接受之方案是promise,我这里连无讨论其的法则,也非讨论她当业务中的应用,而是如取一下它们以组件化框架中所能够起至的来意。

本已经远非谁前端组件化框架可以不考虑异步加载问题了,因为,在前端是世界,加载就是一个缠绕不过去的坎儿,必须发了加载,才能够生出履行进程。每个组件化框架都非可知挡自己的使用者规模膨胀,因此呢应有在框架层面提出解决方案。

咱或许会见动态配置路由,也或在动态加载的路途由于着又引入新的组件,如何决定这些事物的生命周期,值得仔细斟酌,如果以框架层面都异步化,对于编程体验的一致性是产生好处的。将各类接口都promise化,能够以可维护性和而扩展性上提供比较多造福。

咱之前可能熟知XMLHTTP这样的通信接口,这个事物则让广为使用,但是以优雅性等地方,存在部分问题,所以近年来出了代表方案,那即便是fetch。

细节可以参见月影翻译的这首【翻译】这个API很“迷人”——(新的Fetch API)

在不支持之浏览器上,也来github实现的一个polyfill,虽然非备,但足凑合用window.fetch
polyfill

世家可以看出,fetch的接口就是根据promise的,这应当是前端开发人员最为容易接受的方案了。

            class Program

7.5 Isomorphic javascript

其一事物的意思是内外端同构的javascript,也就是说,比如同块界面,可以选取当前端渲染,也得选以后端渲染,值得关注,可以化解像seo之类的题目,但现行尚不可知处理好复杂的景象,持续关注吧。

            {

8. 小结

特别感谢能看此间,以上这些是自家近平年的一对想总结。从技术选型的角度看,做大型Web应用的人数见面生痛,因为当时是一个紧张的年份,目前都部分有框架/库都在不同程度之弱点。当你向未来关押去,发现她都是需要让丢弃,或者给改建的,人无限惨痛之是以明森东西坏,却同时使从中挑选一个来用。@严清
跟@寸志
@题叶讨论了这个问题,认为现在此阶段的技巧选型难开,不如等一阵,我意赞同他们的意见。

选型是难,但是自读书的角度,可当真是老好之一时,能效仿的物太多了,我每天途中都以奋力看有或值得看的事物,可还是看无了,只能全力去与达到一代的步子。
(++前端技术迭代的速更是快,技术不断在晃动,对长远的门类具有严格的考验。在并未好好的出路前对大型项目的总体高风险且不便将控。)

以下一段落,与各位共勉:

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) 父类提供一个方可吃重新写的主意,有子类重写,通过父类,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)新建一个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地图