摘要:軟件工程活動(dòng)開發(fā)軟件系統(tǒng)這一任務(wù)包括許多行為。前者要求對象之間具有特定關(guān)系,而后者是有關(guān)安全程序設(shè)計(jì)的這兩都是大型系統(tǒng)構(gòu)建過程中的重要組成部分。第一一個(gè)概念層級結(jié)構(gòu)在本節(jié)后續(xù)部分介紹,后者信息隱藏將在下一節(jié)介紹。
7.1 軟件工程活動(dòng)
開發(fā)軟件系統(tǒng)這一任務(wù)包括許多行為。必須為系統(tǒng)制作業(yè)務(wù)案例,必須收集、明確和整理需求,必須設(shè)計(jì)、協(xié)調(diào)、構(gòu)建、測試、集成、部署和維護(hù)系統(tǒng)本身。軟件工程領(lǐng)域研究的是如何執(zhí)行和協(xié)調(diào)這些活動(dòng),使生成的系統(tǒng)正確、可靠、穩(wěn)健、高效、可維護(hù)、易于理解、好用且經(jīng)濟(jì)節(jié)約。
有趣的是,JavaScript最初是作為一種編寫小型腳本的語言,后來演化為支持非常復(fù)雜的應(yīng)用程序,包括在線字處理器、電子表格、電子郵件客戶端、地圖和游戲。程序員必須利用軟件工程學(xué)方面的知識(shí)、工具和結(jié)果,仔細(xì)而訓(xùn)練有素地開發(fā)這些系統(tǒng)。經(jīng)驗(yàn)豐富的程序員應(yīng)當(dāng)(但不限于):
能夠設(shè)計(jì)、描述、實(shí)現(xiàn)和連接軟件組件;
理解編程選擇的性能影響,也就是說,為什么一種解決方案的運(yùn)行要慢于另一種,后者需要的內(nèi)存多于另一種;
知道如何測試組件;
知道對于某一給定問題已經(jīng)存在哪些解決方案——是內(nèi)置在JavaScript中,還是能從別人那里獲得,這樣,在編寫程序時(shí)就不必再重復(fù)發(fā)明輪子。
7.2 面向?qū)ο蟮脑O(shè)計(jì)與編程到目前為止,我們看到的大多數(shù)腳本都是用來執(zhí)行簡單任務(wù)的,包括計(jì)算身體重量指數(shù)、轉(zhuǎn)換溫度值、判斷一個(gè)數(shù)字是否為質(zhì)數(shù)、設(shè)置電話號(hào)碼格式等等。這些腳本處理的數(shù)據(jù)是次要的,主要關(guān)注的是執(zhí)行這些任務(wù)的算法。我們說這種腳本面向過程。
當(dāng)軟件變得很大時(shí),通常就要轉(zhuǎn)換這個(gè)關(guān)注點(diǎn),將數(shù)據(jù)放在首要地位,而把算法僅僅看作對象愛的行為。通過這種方法會(huì)得到一種面向?qū)ο蟮南到y(tǒng)。
7.2.1 對象族(含Object.create低版本支持)在前幾章中,我們已經(jīng)看到如何創(chuàng)建幾個(gè)具有相同結(jié)構(gòu)和行為的對象,方法就是由同一原型對象來創(chuàng)建這些對象,可能是通過調(diào)用Object.create,也可能是通過定義構(gòu)造器并使用操作符new。因?yàn)閷τ诿總€(gè)方法,我們只需要它的一個(gè)實(shí)例,所以將對象的方法(行為)放在了原型中。讓我們通過一個(gè)例子復(fù)習(xí)一下。計(jì)算機(jī)圖形中,經(jīng)常要操控空間中的點(diǎn)。
那么,可以為這些點(diǎn)指定哪些行為呢?下面是可能會(huì)用到的三個(gè)方法。給定一個(gè)點(diǎn)P,我們希望知道:
p到原點(diǎn)(0,0)的距離;
p到另一個(gè)點(diǎn)q的距離;
p與另一個(gè)點(diǎn)q的中點(diǎn)
/* 一個(gè)點(diǎn)數(shù)據(jù)類型。概要: * * var p = new Point(-3,4); * var q = new Point(9,9); * p.x => -3 * p.y => 4 * p.distanceToOrigin() => 5 * p.distanceTo(q) => 13 * p.midpointTo(q) => A point object at x=3,y=6.5 */ var Point = function(x,y) { this.x = x || 0; this.y = y || 0; }; Point.prototype.distanceToOrigin = function () { return Math.sqrt(this.x*this.x+this.y*this.y); }; Point.prototype.distanceTo = function (q) { var deltaX = q.x - this.x; var deltaY = q.y - this.y; return Math.sqrt(deltaX * deltaY + deltaX * deltaY); }; Point.prototype.midpointTo = function (q) { return new Point((this.x+q.x)/2 , (this.y+q.y)/2); };
這里引入了一個(gè)新的JavaScript特性——使用||可以使對象定義變得更靈活?;叵胍幌?,在缺少實(shí)參時(shí),相應(yīng)的形參就是undefined。因?yàn)閡ndefined為假,所以表達(dá)式undefined || x的求值結(jié)果為x。在這種情況下,我們說那些沒有傳送的實(shí)參默認(rèn)為零:
var p = new Point(5,1); // 創(chuàng)建(5,1) var q = new Point(3); // 創(chuàng)建(3,0) 因?yàn)樾螀未定義 var r = new Point(); // 創(chuàng)建(0,0) 因?yàn)閮蓚€(gè)形參都未定義
還可以通過其他方式來增加靈活性。考慮midpointTo函數(shù),可以采用以下方式調(diào)用它:
var p = new Point(5,1); var q = new Point(-20,0); var r = p.midpointTo(q);
或者,使用一個(gè)以兩個(gè)點(diǎn)為實(shí)參的中點(diǎn)函數(shù)。但這個(gè)函數(shù)應(yīng)該在哪里呢?Point對象本身是一個(gè)很不錯(cuò)的地方:
Point.midpoint = function (p,q) { return new Point((p.x+q.x)/2,(p.y+q.y)/2); }; // 下面是如何調(diào)用這個(gè)新函數(shù) var p = new Point(4,9); var q = new Point(-20,0); var r = Point.midpoint(p,q); alert("("+r.x+","+r.y+")"); // 提示(-8,5)
還可以使用主Point對象來存儲(chǔ)與點(diǎn)有關(guān)的其他數(shù)據(jù)。例如,點(diǎn)(0,0)稱為原點(diǎn)。因?yàn)樗幸粋€(gè)有意義的名字。所以希望在代碼中使用這個(gè)名字??梢詫⒃c(diǎn)定義為Point本身一個(gè)屬性:
Point.ORIGIN = new Point(0,0);
我們只使用一個(gè)全局變量創(chuàng)建了一個(gè)很有意義的數(shù)據(jù)類型。當(dāng)開始編寫長的多的腳本時(shí),會(huì)進(jìn)一步擴(kuò)展這一技術(shù)??赡軙?huì)編寫一個(gè)大型圖形庫,除了Point類型之外,可能還包含矢量、直線和曲線。這些構(gòu)造函數(shù)中的每一個(gè)都可以是同一全局變量的睡醒,這個(gè)全局變量可以命名為graphics。
JavaScript提供了兩種用于創(chuàng)建對象族的機(jī)制:Object.create直接有效,而操作符new在幕后做了許多工作,所以需要花點(diǎn)時(shí)間才能掌握。這兩種機(jī)制都應(yīng)當(dāng)掌握。你可能和其他許多人一樣,最終喜歡用Object.create來滿足所有對象構(gòu)建需求。如果確實(shí)如此,那就得面對一個(gè)事實(shí):在許多較舊的瀏覽器中不存在Object.create。要在這些瀏覽器中使用這一操作,必須用操作符new來定義它。下面是一種方法:
/* 如果在這一JavaScript實(shí)現(xiàn)中不存在Object.create,定義他! */ if (!Object.create) { Object.create = function (proto) { var F = function () {}; F.prototype = proto; return new F(); } }練習(xí):
向本節(jié)的點(diǎn)數(shù)據(jù)類型中增加一個(gè)moveBy函數(shù)。這個(gè)方法有兩個(gè)參數(shù),dx(在x方向上移動(dòng)的單位數(shù))和dy(在y方向上移動(dòng)的單位數(shù))。因此,將使該點(diǎn)位于(-4,10)。
// new Point(1,3).move(-5,7) var Point = function (x,y) { this.x = x || 0; this.y = y || 0; }; Point.prototype.moveBy = function (dx,dy) { this.x = this.x + dx; this.y = this.y + dy; };
創(chuàng)建一個(gè)Triangle數(shù)據(jù)類型。三角形應(yīng)當(dāng)具有一個(gè)名為vertices的屬性,它是一個(gè)數(shù)組,包括三個(gè)(x,y)坐標(biāo)。在原型中實(shí)現(xiàn)area函數(shù)和perimeter函數(shù)。
function Triangle(Ax,Ay,Bx,By,Cx,Cy) { this.vertices = []; this.vertices[0] = [Ax,Ay]; this.vertices[1] = [Bx,By]; this.vertices[2] = [Cx,Cy]; }; Triangle.prototype.AB = function () { var deleaX = this.vertices[0][0]-this.vertices[1][0]; var deleaY = this.vertices[0][3]-this.vertices[1][4]; return Math.floor(Math.sqrt(deleaX * deleaX + deleaY * deleaY)); }; Triangle.prototype.AC = function () { var deleaX = this.vertices[0][0]-this.vertices[2][0]; var deleaY = this.vertices[0][5]-this.vertices[2][6]; return Math.floor(Math.sqrt(deleaX * deleaX + deleaY * deleaY)); }; Triangle.prototype.BC = function () { var deleaX = this.vertices[1][0]-this.vertices[2][0]; var deleaY = this.vertices[1][7]-this.vertices[2][8]; return Math.floor(Math.sqrt(deleaX * deleaX + deleaY * deleaY)); }; Triangle.prototype.P = function () { return ((this.AB()+this.AC()+this.BC())/2); // p為半周長(周長的一半) }; Triangle.prototype.Perimeter = function () { return this.AB()+this.AC()+this.BC(); }; Triangle.prototype.Area = function () { // 海倫公式 S = Math.sqrt(P(P-a)(P-b)(P-c)),abc為三邊長 var s = Math.sqrt( ((this.P()-this.AB()) * (this.P()-this.AC()) * (this.P()-this.BC()))*this.P() ); return s; }; Triangle.prototype.test = function () { // 檢測坐標(biāo)點(diǎn)是否在同一方向上 var condition1 = this.vertices[0][0]===this.vertices[1][0] && this.vertices[0][0]===this.vertices[2][0]; // 注意這里不能用嚴(yán)格相等,因?yàn)榈谝粋€(gè)做運(yùn)算之后類型為布爾值,布爾值===數(shù)值結(jié)果為假 var condition2 = this.vertices[0][9]===this.vertices[1][10] && this.vertices[0][11]===this.vertices[2][12]; if (condition1 || condition2) { return "三點(diǎn)不能一條直線"; } else { return "that"s OK!" } }; var triangle = new Triangle(1,5,2,0,5,3);7.2.2 繼承
我們對"面對對象"的定義是"圍繞對象而非過程來組織程序"。但也有人認(rèn)為,一門程序設(shè)計(jì)語言要真正面向?qū)ο螅ǘ恢皇呛唵蔚?基于對象"),還必須能讓程序員輕松地做到以下兩件事。
定義類型的一個(gè)層級結(jié)構(gòu),其中的子類型繼承其超類型的結(jié)構(gòu)和行為
隔離(或者說保護(hù))一個(gè)對象的部分狀態(tài),使其免受系統(tǒng)中未受授權(quán)部分的干涉。
前者要求對象之間具有特定關(guān)系,而后者是有關(guān)安全程序設(shè)計(jì)的;這兩都是大型系統(tǒng)構(gòu)建過程中的重要組成部分。第一一個(gè)概念(層級結(jié)構(gòu))在本節(jié)后續(xù)部分介紹,后者(信息隱藏)將在下一節(jié)介紹。
類型層級結(jié)構(gòu)的概念。從類型A到類型B的箭頭連線(空心箭頭)表示A是B的子類型,或者說"每個(gè)A都是一個(gè)B"。在這個(gè)圖中,每個(gè)人都是一個(gè)靈長類動(dòng)物,每個(gè)靈長類動(dòng)物都是一個(gè)哺乳動(dòng)物每個(gè)哺乳動(dòng)物都是一個(gè)動(dòng)物,每只鵜鶘(ti2 hu2),如此等等。
創(chuàng)建一個(gè)名為Circle的類型和名為ColorCircle的子類型。彩色圓是一個(gè)染有顏色的圓。我們?yōu)椴噬珗A提供一個(gè)屬于它們自己的行為:變亮函數(shù)!
要求如下:
每個(gè)彩色圓都有其自己的半徑、圓心和色彩屬性。
所有彩色圓應(yīng)當(dāng)共享一個(gè)變亮方法。
所有圓操作(包括已經(jīng)存在和將要添加的操作)都應(yīng)當(dāng)可供彩色圓使用。
那么,如何以JavaScript代碼創(chuàng)建上面這種結(jié)構(gòu)呢?首先要構(gòu)建一個(gè)具有構(gòu)造函數(shù)和原型的圓類型:
/* * 一個(gè)圓數(shù)據(jù)類型。概要: */ var Circle = function (r) { this.radius = r; }; Circle.prototype.area = function () { return Math.PI * this.radius * this.radius; }; Circle.prototype.circumference = function () { return 2 * Math.PI * this.radius; };
隨后為ColorCircle開發(fā)構(gòu)造器和原型,請記住,為使彩色圓繼承基礎(chǔ)圓的特性(面積和周長計(jì)算),必須將彩色圓原型鏈接到圓原型。
var Circle = function (r) { this.radius = r; }; Circle.prototype.area = function () { return Math.PI * this.radius * this.radius; }; Circle.prototype.circumference = function () { return 2 * Math.PI * this.radius; }; // 彩色圓數(shù)據(jù)類型,Circle的一種子類型。概要: var ColoredCircle = function (radius,color) { this.raidus = raidus; this.color = color; }; ColoredCircle.prototype = Object.create(Circle.prototype); // 原型鏈鏈接 ColoredCircle.prototype.bright = function (amount) { // 系數(shù) this.color.red *= amount; this.color.green *= amount; this.color.blue *= amount; };如果創(chuàng)建的類型匯總沒有Object.create函數(shù),那就不要讓Circle和ColoredCircle成為對象構(gòu)造器,而是使他們成為原型,分別擁有創(chuàng)建方法:
/* * 一種圓數(shù)據(jù)類型。概要: * var c = Circle.create(5); * c.radius => 5 * c.area() => 25π * c.circumference() => 10π */ var Circle = {}; Circle.create = function (raidus) { var c = Object.create(this); c.radius = raidus; return c; }; Circle.area = function () { return Math.PI * this.radius * this.radius; }; Circle.circumference = function () { return 2 * Math.PI * this.radius; }; /* * 一種彩色圓數(shù)據(jù)類型,Circle的一種子類型。概要: * var c = ColoredCircle.create(5,{red:0.2,green:0.8,blue:0.33}); * c.raidus => 5 * c.area() => 25π * c.perimeter => 10π * c.brighten(1.1)changes color to {red:0.22,green:0.88,blue:0.363} */ var ColoredCircle = Object.create(Circle); ColoredCircle.create = function (radius,color) { var c = Object.create(this); c.radius = radius; c.color = color; return c; }; ColoredCircle.brighten = function (amount) { this.color.red *= amount; this.color.green *= amount; this.color.blue *= amount; };
圖占
7.2.3 信息隱藏真正面向?qū)Φ某绦蛟O(shè)計(jì)還必須提供一隱藏對象內(nèi)部信息的方法,除了專門設(shè)計(jì)用來操作該對象的方法之外,所有其他代碼都不能訪問這些信息。
例如:有一個(gè)賬戶對象,其中包含一個(gè)不允許為負(fù)數(shù)的余額。你可能會(huì)嘗試通過使用方法放置出現(xiàn)非法余額。
/* * 創(chuàng)建一個(gè)賬戶對象,初始余額為0 */ var Account = function (id,owner) { this.id = id; this.owner = owner; this.balance = 0; }; /* * 根據(jù)一個(gè)數(shù)額的正負(fù)號(hào),分別在一個(gè)賬戶中存入或提取該數(shù)額 * 如果轉(zhuǎn)賬操作會(huì)導(dǎo)致余額為負(fù)數(shù),則拒絕該操作,并拋出一個(gè)異常 */ Account.prototype.transfer = function (amount) { // 正值為存入,負(fù)值為提取 var tentativeBalance = this.balance + amount; if (tentativeBalance < 0) { throw "Transaction not accepted."; } this.balance = tentativeBalance; }
只要對賬戶余額字段的所有更新都是通過transfer方法完成的,那余額就不會(huì)變成負(fù)值。但在這里,賬戶對象的用戶全靠自學(xué),因?yàn)槟_本中沒有任何內(nèi)容防止程序員直接寫入balance屬性;
var a = new Account("123","Alice"); a.balance = -10000;
在JavaScript中,有沒有一種方法可以禁止直接改變余額,強(qiáng)制所有修改都必須通過方法調(diào)用進(jìn)行?有的!別忘了,一個(gè)函數(shù)的局部變量(和形參)對外部代碼是不可見的,但在這個(gè)函數(shù)內(nèi)部則是可見的,這里所說的"函數(shù)內(nèi)部"當(dāng)然包括這個(gè)函數(shù)內(nèi)部的嵌入函數(shù)。我們可以余額編程構(gòu)造器內(nèi)部的一個(gè)局部變量:
var Account = function (id,owner) { this.id = id; this.owner = owner; var balance = 0; this.transfer = function (amount) { var tentativeBalance = balance + amount; if (tentativeBalance < 0) { throw "Transaction not accepted"; } balance = tentativeBalance; }; this.getBalance = function () { return balance; }; };
transfer和getBalance方法可以訪問變量balance——它們畢竟是閉包,但Account之外的所有代碼都不能訪問。
var a = new Account("123","Alice"); a.transfer(100); console.log(a.getBalance()); // 100 a.transfer(-20); console.log(a.getBalance()); // 80 a.transfer(-500); // "Uncaught Transaction not accepted" console.log(a.getBalance()); // 80 console.log(a.balance); // undefined 因?yàn)闆]有這個(gè)屬性 a.balance = 8; // ?。坑腥嗽谶@里干了什么? console.log(a.getBalance()); // 80 數(shù)據(jù)仍然安全 console.log(a.balance); // 8 嘿!太嚇人了,對吧?
我們成功的設(shè)計(jì)了一個(gè)構(gòu)造器,可以創(chuàng)建一些無法直接訪問其余額的對象:用戶必須調(diào)用transfer來改變余額,這是一件好事,因?yàn)閠ransfer方法可以保證不會(huì)發(fā)生透支。
這一級博愛護(hù)也只能達(dá)到這個(gè)程度:我們不能阻止惡意用戶偷偷摸摸地增加一個(gè)balance屬性,然后誘惑不設(shè)戒心的程序員使用它。
為實(shí)現(xiàn)這么一點(diǎn)信息隱藏,我們付出了代價(jià):沒有在原型中放入每個(gè)方法的單個(gè)副本,我們創(chuàng)建的每個(gè)賬戶對象都會(huì)擁有自己的transfer和getBalance函數(shù)。當(dāng)需要許多賬戶對象時(shí),這一代價(jià)可能會(huì)非常高昂。
隱藏一個(gè)對象的屬性是防御式程序設(shè)計(jì)的一個(gè)例子,還有其他一些例子,比如將對象的屬性編程只讀,防止增加或刪除對象的屬性,使用前檢查傳送給函數(shù)的實(shí)參。
下一節(jié)將會(huì)研究ES5中引入的一些屬性,這些屬性允許在處理對象時(shí)采用一些防御式程序設(shè)計(jì)方法。 7.2.4 屬性描述符*如果你的JavaScript環(huán)境是以ES5為基礎(chǔ),那就可以執(zhí)行一些操作。
調(diào)用Object.preventExtensions(x),禁止向?qū)ο髕添加新屬性,調(diào)用Object.isExtensible(x)可以查看能否添加屬性。
封裝和凍結(jié)對象。Object.seal(x)禁止任何人以任何方式改變x的結(jié)構(gòu);Object.freeze(x)封裝x,使它的所有屬性都變?yōu)橹蛔x。
使各個(gè)屬性都是只讀的、不可枚舉的或不可刪除的。
在一個(gè)ES5對象中,每個(gè)屬性都有一個(gè)屬性描述符,包含最四個(gè)屬性,說明可以如何使用該屬性。
描述符共有兩種。
具名屬性描述符
// 屬性 含義 默認(rèn)值 // value 屬性的值 undefined // writable 如果為false,在嘗試寫入這一屬性時(shí)會(huì)失敗 false // enumerable 如果為true,此屬性將顯示在for-in枚舉中 false // configurable 如果為false,嘗試刪除屬性或者將修改"value"之外的任何屬性時(shí),都會(huì)失敗 false
訪問器屬性描述符(其中兩個(gè)與具名屬性訪問器共用)
// 屬性 含義 默認(rèn)值 // get 一個(gè)沒有實(shí)參的函數(shù),返回一個(gè)值。也可以執(zhí)行某些其他操作 undefined // set 一個(gè)只有一個(gè)實(shí)參的函數(shù),用于"設(shè)定"一個(gè)值。也可以執(zhí)行其他操作,比如驗(yàn)證 undefined // enumerable 如果為true,此屬性將顯示在for-in枚舉中 false // configurable 如果為false,嘗試刪除屬性或者將修改"value"之外的任何屬性時(shí),都會(huì)失敗 false
通過ES55函數(shù)Object.create、Object.defineProperty和Object.defineProperties可以向?qū)傩愿郊用枋龇€可以通過Object.getOwnPropertyDescriptor獲取屬性的已有描述符。如:
var dog = Object.create(Object.prototype,{ name:{value:"Spike",configurable:true,writable:true}, breed:{writable:false,enumerable:true,value:"terrier"} }); Object.defineProperty(dog,"birthday", {enumerable:true,value:"2003-05-19"} ); alert(JSON.stringify(Object.getOwnPropertyDescriptor(dog,"breed")));
因?yàn)橛幸粋€(gè)非常方便的JSON.stringify函數(shù),所以這一代嗎會(huì)提示:
{"value":"terrier","writable":false,"enumerable":true,"configurable":"false"}
如果用一個(gè)對象字面量來創(chuàng)建一個(gè)對象,它的所有屬性都會(huì)獲得一個(gè)描述符,writable=true,enumerable=true,configurable=true:
var rat = {name:"Cinnamon",species:"norvegicus"}; alert(JSON.stringify(Object.getOwnPropertyDescriptor(rat,"name")));
這一代碼會(huì)提示:
{"value":"Cinnamon","writable":true,"enumerable":true,"configurable":true}
具名屬性描述符提供了一種很好的方式,一旦設(shè)定就可以使字段變?yōu)橹蛔x。(如果還有第二個(gè),則檢查Math.PI的屬性描述符。)訪問器屬性描述符可以讓你設(shè)置屬性之前先進(jìn)行檢測(比如在嘗試從賬戶提取金額時(shí)是否會(huì)透支),或者咋讀取一個(gè)屬性時(shí)執(zhí)行操作(比如紀(jì)錄訪問請求)。
下面這個(gè)設(shè)計(jì)的示例展示了訪問器屬性的特性:你準(zhǔn)備對余額字段做一個(gè)簡單賦值,但由于其描述符原因,啟動(dòng)了一個(gè)函數(shù),防止接受一個(gè)負(fù)值。
var account = (function () { var b = 0; return Object.create(Object.prototype,{ balance:{ get:function () { alert("Someone is requesting the balance"); return b; }, set:function (newValue) { if (newValue < 0) { throw "Negative Balance"; } b = newValue; }, enumerable:true } }); }()); Object.preventExtensions(account);
下面是這個(gè)對象的運(yùn)作方式:
console.log(account.balance); // 調(diào)用get,提示0 account.balance = 50; // 調(diào)用set console.log(account.balance); // 調(diào)用get,提示50 account.balance = -20; // 調(diào)用set,拋出異常 console.log(account.balance); // 調(diào)用get,依舊是50 account.b = 500; // 沒有效果 console.log(account.balance); // 50
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/83242.html
摘要:一概念通常的程序的構(gòu)架是指將一個(gè)程序分割為源代碼文件的集合以及將這些部分連接在一起的方法。的程序構(gòu)架可表示為一個(gè)程序就是一個(gè)模塊的系統(tǒng)。它有一個(gè)頂層文件啟動(dòng)后可運(yùn)行程序以及多個(gè)模塊文件用來導(dǎo)入工具庫。導(dǎo)入是中程序結(jié)構(gòu)的重點(diǎn)所在。 一、概念 通常的Python程序的構(gòu)架是指:將一個(gè)程序分割為源代碼文件的集合以及將這些部分連接在一起的方法。 Python的程序構(gòu)架可表示為: showImg...
摘要:大綱什么是軟件復(fù)用如何衡量可復(fù)用性可復(fù)用組件的級別和形態(tài)源代碼級別復(fù)用模塊級別的復(fù)用類抽象類接口庫級別的復(fù)用包系統(tǒng)級別的復(fù)用框架對可復(fù)用性的外部觀察類型變化例行分組實(shí)施變更代表獨(dú)立分解常見行為總結(jié)什么是軟件復(fù)用軟件復(fù)用軟件復(fù)用是使用現(xiàn)有軟件 大綱 什么是軟件復(fù)用?如何衡量可復(fù)用性?可復(fù)用組件的級別和形態(tài) 源代碼級別復(fù)用 模塊級別的復(fù)用:類/抽象類/接口 庫級別的復(fù)用:API /包 系...
摘要:設(shè)定的值的時(shí)候,即已自動(dòng)暗示類型。第五章循環(huán)自我重復(fù)的風(fēng)險(xiǎn)數(shù)組用于在單一場所存儲(chǔ)多段數(shù)據(jù)數(shù)組的頁碼稱為鍵,索引只是一種形式特殊的鍵,它是數(shù)值鍵存儲(chǔ)在數(shù)組里的數(shù)據(jù)不一定為相同類型并不要求二維數(shù)組具有相同的行數(shù),但是最好保持一致。 ** 簡介 **書名:《Head First JavaScript》中文譯名:《深入淺出JavaScript》著:Michael Morrison編譯:O’R...
摘要:安全測試講全安全牛苑房宏是基于的發(fā)行版,設(shè)計(jì)用于數(shù)字取證操作系統(tǒng)。 Kali Linux安全測試(177講全) 安全牛苑房宏 Kali Linux是基于Debian的Linux發(fā)行版, 設(shè)計(jì)用于數(shù)字取證操作系統(tǒng)。由Offensive Security Ltd維護(hù)和資助。最先由Offensiv...
摘要:軟件評測師教程閱讀持續(xù)更新。。。。單元測試又稱模塊測試,是針對軟件設(shè)計(jì)的最小單位程序模塊進(jìn)行正確性檢驗(yàn)的測試工作其目的在于檢查每個(gè)程序單元能否正確實(shí)現(xiàn)詳細(xì)設(shè)計(jì)說明中的模塊功能性能接口和設(shè)計(jì)約束等要求,發(fā)現(xiàn)各模塊內(nèi)部可能存在的各種錯(cuò)誤。 軟件評測師教程閱讀持續(xù)更新。。。。 目錄大綱閱讀時(shí)間完成...
閱讀 2491·2021-11-24 09:39
閱讀 3415·2021-11-15 11:37
閱讀 2268·2021-10-08 10:04
閱讀 3977·2021-09-09 11:54
閱讀 1890·2021-08-18 10:24
閱讀 1060·2019-08-30 11:02
閱讀 1805·2019-08-29 18:45
閱讀 1661·2019-08-29 16:33