新建一個(gè)android工程:D_session;它有一個(gè)activity:D_sessionActivity;package名:com.mysession
二.測(cè)試工程:
新建一個(gè)
測(cè)試工程:D_sessionTest, 類(lèi)型是android test project;
1. menifest文件:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mysession.test" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.mysession" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <uses-library android:name="android.test.runner" /> </application> </manifest> |
2. 一個(gè)base activity 來(lái)定義各種模擬測(cè)試者的動(dòng)作和判斷測(cè)試結(jié)果,各個(gè)測(cè)試類(lèi)都繼承該類(lèi):
package com.mysession.test; import android.app.Activity; import android.app.Instrumentation; import android.app.Instrumentation.ActivityMonitor; import android.content.Intent; import android.test.InstrumentationTestCase; import android.test.TouchUtils; import android.widget.Button; import android.widget.TextView; import com.mysession.D_sessionActivity; public class SessionActivityTest extends InstrumentationTestCase { private Instrumentation mInstrumentation; private ActivityMonitor mSessionMonitor; private Activity mCurrentActivity, mSessionActivity; private String TextNotEqual = "text not equal."; private static final String PackageName = "com.mysession"; @Override protected void setUp() throws Exception { // 初始化 super.setUp(); if (mInstrumentation == null) { mInstrumentation = getInstrumentation(); } mSessionActivity = null; } @Override protected void tearDown() throws Exception { super.tearDown(); //釋放資源 closeActivity(mSessionActivity); mCurrentActivity = null; } private void closeActivity(Activity activity) { if(activity != null){ activity.finish(); activity = null; } } public void openSessionActivity() { // 打開(kāi)session activity try { setUp(); } catch (Exception e) { e.printStackTrace(); } mSessionMonitor = mInstrumentation.addMonitor( D_sessionActivity.class.getName(), null, false); Intent intent = new Intent(Intent.ACTION_MAIN); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setClassName(PackageName, D_sessionActivity.class.getName()); mInstrumentation.startActivitySync(intent); mSessionActivity = getInstrumentation().waitForMonitor(mSessionMonitor); assertNotNull(mSessionActivity); mCurrentActivity = mSessionActivity; } //判斷text是否正確 public void assertTextEqual(int resId, String strText) { TextView textView = (TextView) mCurrentActivity.findViewById(resId); assertNotNull(textView); assertEquals(TextNotEqual, strText, textView.getText().toString()); }; // 模擬按鈕點(diǎn)擊事件 public void clickButton(int resId){ Button button = (Button) mCurrentActivity.findViewById(resId); assertNotNull(button); TouchUtils.clickView(this, button); } } |
3. 各個(gè)測(cè)試類(lèi):
測(cè)試類(lèi)一:
package com.mysession.test.cases; import com.mysession.R; import com.mysession.test.SessionActivityTest; public class MyCase1 extends SessionActivityTest { public void testCase1() { openSessionActivity(); assertTextEqual(R.id.etUrl, "http://172.20.230.5/iportal/samples/jsapi/mobile.html"); } public void testCase3() { openSessionActivity(); clickButton(R.id.btnLoad); clickButton(R.id.btnHistory); } } |
測(cè)試類(lèi)二:
package com.mysession.test.cases; import com.mysession.R; import com.mysession.test.SessionActivityTest; public class MyCase2 extends SessionActivityTest{ public void testCase2() { openSessionActivity(); clickButton(R.id.btnLoad); } } |
三. 有些動(dòng)作(如點(diǎn)擊menu)需要通過(guò)包robotium-solo-1.8.0.jar來(lái)完成。
所以要在Build Path->Configure Build Path…中導(dǎo)入:robotium-solo-1.8.0.jar
程序中:
private Solo solo;
solo = new Solo(getInstrumentation(),getActivity);
就可以使用solo了, 如:
solo.clickOnMenuItem(text);
solo.goBack();
目前有很多Web UI自動(dòng)化
測(cè)試框架,如WatiN,Selinimu,WebDriver等,這些框架都可以操作Web中的控件,模擬用戶輸入,點(diǎn)擊等操作,實(shí)現(xiàn)Web自動(dòng)化測(cè)試。其實(shí)這些工具的原理都一樣,都是通過(guò)調(diào)用IE COM接口和HTMLDOM 對(duì)IE瀏覽器以及WEB測(cè)試對(duì)象的操作。 本文介紹脫離這些
自動(dòng)化測(cè)試框架,通過(guò)AutoIT直接使用IE COM接口結(jié)合HTML DOM對(duì)IE瀏覽器以及WEB對(duì)象進(jìn)行自動(dòng)化測(cè)試的方法。
1.IE常用操作
首先新建一個(gè)IE COM對(duì)象,配置IE窗口屬性,模擬用戶同時(shí)跳轉(zhuǎn)至相應(yīng)的頁(yè)面同時(shí)進(jìn)行相應(yīng)操作。訪問(wèn)頁(yè)面時(shí),需要等待頁(yè)面加載完成后再進(jìn)行操作。這里我們可以使用IE COM的BUSY屬性檢查瀏覽器是否處于加載狀態(tài),再進(jìn)行相應(yīng)的操作。示例代碼如下:
2.利用DOM操作測(cè)試對(duì)象
現(xiàn)在已經(jīng)會(huì)使用IE COM組件來(lái)對(duì)IE瀏覽器進(jìn)行自動(dòng)化的操作,但是對(duì)于瀏覽器頁(yè)面中的測(cè)試對(duì)象IE COM是無(wú)法對(duì)其進(jìn)行操作的,這個(gè)時(shí)候就需要使用HTML DOM來(lái)對(duì)其進(jìn)行操作。
2.1 HTML DOM簡(jiǎn)介
HTML DOM是HTML Document Object Model(文檔對(duì)象模型)的縮寫(xiě),它將網(wǎng)頁(yè)中的各個(gè)元素都看作一個(gè)個(gè)對(duì)象,從而使網(wǎng)頁(yè)中的元素也可以被計(jì)算機(jī)語(yǔ)言獲取或者編輯。 常用DOM 屬性如下:
className.同一樣式規(guī)則的元素用相同的類(lèi)名。可以通過(guò)className快速過(guò)濾出一組類(lèi)似的元素。
document.用于指向包含當(dāng)前元素的文檔對(duì)象。
id.當(dāng)前元素的標(biāo)識(shí)。如果文檔中包含多個(gè)相同id的元素,則返回一個(gè)數(shù)組。
innerHTML.用于指向當(dāng)前元素的開(kāi)始標(biāo)記和結(jié)束標(biāo)記之間的所有文本和HTML標(biāo)簽。
innerText.用于指向當(dāng)前元素的開(kāi)始標(biāo)記和結(jié)束標(biāo)記之間的所有文本和HTML標(biāo)簽。
offsetHeight, offsetWidth.元素的高度和寬度。
offsetLeft, offsetTop.當(dāng)前元素相同對(duì)于父親元素的左邊位置和頂部位置。
outerHTML.當(dāng)前元素的開(kāi)始標(biāo)記和結(jié)束標(biāo)記之間的所有文本和HTML標(biāo)簽。
outerText.當(dāng)前元素的開(kāi)始標(biāo)記和結(jié)束標(biāo)記之間的所有文本,但不包括HTML標(biāo)簽。
parentElement.當(dāng)前元素的父親元素。
sourceIndex.元素在document.all集合中的索引(index)。
style.元素的樣式表單屬性。
tagName.當(dāng)前元素的標(biāo)簽名。
title.在IE中,代表元素的tool tip文本
常用DOM方法如下:
click().模擬用戶對(duì)當(dāng)前元素的鼠標(biāo)點(diǎn)擊。
contains(element).用于判斷當(dāng)前元素是否包含指定的元素。
getAttribute(attributeName, caseSensitive).返回當(dāng)前元素所包含的某個(gè)屬性,參數(shù)attributeName為屬性名、caseSensitive表示是否大小寫(xiě)敏感。
setAttribute(attributeName, value, caseSenstive). 設(shè)置當(dāng)前元素的屬性。
常用DOM 集合如下:
All[].當(dāng)前元素中包含的所有HTML元素的數(shù)組。
children[].當(dāng)前元素包含的子元素。
2.2 種方法對(duì)比
2.2.1getElementByID
getElementByID( )方法可根據(jù)指定的id屬性值得到對(duì)象。 首先需要分析頁(yè)面,在Chome瀏覽器中選擇相應(yīng)的網(wǎng)頁(yè)元素點(diǎn)擊右鍵選擇"審查元素"(或使用IE Develop Toolbar或者firebug等插件亦可),即可得到頁(yè)面控件的ID等信息。

通過(guò)getElementByID方法獲取百度搜索框及搜索按鈕對(duì)象,并對(duì)其進(jìn)行輸入及點(diǎn)擊操作,從而完成搜索操作。示例代碼如下:
2.2.2getElementsByName
getElementsByName( )方法可返回帶有指定名稱(chēng)的對(duì)象的集合。
同樣獲取網(wǎng)頁(yè)元素name后,即可通過(guò)getElementsByName方法獲取定位對(duì)象,并對(duì)其進(jìn)行操作(與getElementByID返回的單個(gè)對(duì)象不同,getElementsByName返回的是一個(gè)元素的集合,需要通過(guò)遍歷對(duì)象才能對(duì)其進(jìn)行操作):
2.2.3getElementsByTagName
getElementsByTagName( )方法通過(guò)查找整個(gè)HTML文檔中的任何HTML元素,傳回指定名稱(chēng)的元素集合。 因此也可使用getElementsByTagName獲取TAG名,通過(guò)得到相同類(lèi)型的元素及在遍歷中進(jìn)行判斷控件類(lèi)型并進(jìn)行操作:

2.3 利用FORM名來(lái)獲取對(duì)象元素
使用FORM名來(lái)獲取對(duì)象元素會(huì)大大簡(jiǎn)化我們的腳本。首先查看百度的搜索框?qū)?yīng)的FORM名,得到FORM名為f:
通過(guò)如下簡(jiǎn)單的腳本,同樣可以達(dá)到相同的效果:
2.4 訪問(wèn)Web頁(yè)面的Script腳本變量
通過(guò)DOM還可以直接訪問(wèn)Web頁(yè)面中的JavaScript或者VBScript中的變量。首先打開(kāi)百度的源文件:
可以看到在百度源文件的JavaScript腳本中定義了一個(gè)變量為k,并且賦值為d.f.wd(實(shí)際上就是百度搜索框?qū)ο螅D敲纯梢灾苯邮褂胮arentWindow來(lái)訪問(wèn)Web頁(yè)面Script中的變量k,對(duì)百度搜索框進(jìn)行自動(dòng)測(cè)試:
3 總結(jié)
本文主要介紹了利用IE的COM以及HTML DOM來(lái)自動(dòng)化IE瀏覽器,以及對(duì)瀏覽器的一些控件對(duì)象進(jìn)行自動(dòng)化的操作,包括IE瀏覽器常用操作、利用DOM操作測(cè)試對(duì)象、利用FORM名來(lái)獲取對(duì)象元素、訪問(wèn)Web頁(yè)面的Script腳本變量等。 直接操作IE COM來(lái)實(shí)現(xiàn)Web自動(dòng)化,不僅有助于有助于理解Web頁(yè)面自動(dòng)化測(cè)試框架的運(yùn)行原理,還能脫離這些自動(dòng)化測(cè)試框架自己快速建立一個(gè)輕量型的自動(dòng)化測(cè)試程序,從而真正的提高測(cè)試效率。
原文鏈接:http://lovesoo.org/web-automation-testing-principle.html
測(cè)試是一個(gè)很重要的問(wèn)題,我覺(jué)得:一個(gè)程序員行不行,關(guān)鍵看他會(huì)不會(huì)調(diào)試。程序的測(cè)試都是從小范圍入手然后向四面八方入手,一點(diǎn)點(diǎn)的向外擴(kuò)展,直至最后程序整體運(yùn)行良好。這只是在下的一點(diǎn)愚見(jiàn)。以前進(jìn)行調(diào)試時(shí)總是在程序中寫(xiě)個(gè)main方法,然后進(jìn)行測(cè)試,以前學(xué)過(guò)一個(gè)Junit單元測(cè)試,沒(méi)想起來(lái)用,今天看見(jiàn)老師的代碼中有這個(gè)
單元測(cè)試,所以下來(lái)了看了看以前的代碼并上網(wǎng)查了查有關(guān)Junit的東西,在此簡(jiǎn)單的說(shuō)一下。以MyElipse 8.5 進(jìn)行說(shuō)明。
1.新建一個(gè)project,然后右擊選擇properties-----Java Build Path-----Libraries---AddLibrary---Junit,將Junit插件添加到該項(xiàng)目中。
2.在project中建立一個(gè)JDemo.java 和
Test.java,JDemo中由一個(gè)簡(jiǎn)單的方法add(),Test要繼承TestCase,代碼如下:
JDemo.java package com.bx.testjunit; public class JDemo { int a; int b; int result; public int add(int a,int b){ result = a + b; return result; } } Test.java package com.bx.testjunit; import junit.framework.TestCase; import org.junit.After; import org.junit.Before; public class Test extends TestCase{ @Before public void setUp() throws Exception { System.out.println("Test :setUp"); } @After public void tearDown() throws Exception { System.out.println("Test :tearDown"); } public void test(){ JDemo a = new JDemo(); assertEquals(6,a.add(3, 3)); } } |
3.運(yùn)行,右擊Junit Test,在控制臺(tái)上會(huì)出來(lái)一個(gè)Junit選項(xiàng)卡,如果出現(xiàn)綠顏色的bar則說(shuō)明程序正確,如果是紅顏色的bar則說(shuō)明程序錯(cuò)誤,需進(jìn)行檢錯(cuò)。
上面的程序用的是Junit3,必須繼承TestCase
下面看一個(gè)Junit4的例子
package com.bx.service; import org.junit.Test; public class HelloWorld { @Test public void test(){ System.out.println("HelloWord :test"); } } |
Junit4不需要繼承TestCase,只需使用@Test標(biāo)注的expected屬性。
1、項(xiàng)目進(jìn)度
1.1測(cè)試執(zhí)行階段
寫(xiě)清楚當(dāng)前階段預(yù)計(jì)在什么時(shí)候結(jié)束(在可控的情況下,如果不可控或者不可預(yù)測(cè),說(shuō)明風(fēng)險(xiǎn)在哪里)
寫(xiě)清楚當(dāng)前測(cè)試了哪個(gè)模塊,還有哪些模塊沒(méi)有測(cè)試(一般都是先測(cè)試優(yōu)先級(jí)高的模塊)
寫(xiě)清楚下個(gè)星期的測(cè)試計(jì)劃是什么
2、測(cè)試情況
2.1 再介紹一下本周的測(cè)試模塊
2.2 寫(xiě)清楚當(dāng)前模塊的質(zhì)量情況:open了多少bug,fix了多少,close了多少。bug的趨勢(shì)是什么(后期應(yīng)當(dāng)收斂,在前期如果未收斂,解釋未收斂的原因)
2.3 本周遇到的問(wèn)題是什么(風(fēng)險(xiǎn)是什么)
3、貼圖
3.1 相關(guān)圖片,有需要解釋的進(jìn)行解釋?zhuān)ㄈ鐁eopen的bug,高級(jí)別的bug)
1.概述
一個(gè)軟件設(shè)計(jì)的好壞,我想很大程度上取決于它的整體架構(gòu),而這個(gè)整體架構(gòu)其實(shí)就是你對(duì)整個(gè)宏觀商業(yè)業(yè)務(wù)的抽象框架,當(dāng)代表業(yè)務(wù)邏輯的高層抽象層結(jié)構(gòu) 合理時(shí),你底層的具體實(shí)現(xiàn)需要考慮的就僅僅是一些算法和一些具體的業(yè)務(wù)實(shí)現(xiàn)了。當(dāng)你需要再開(kāi)發(fā)另一個(gè)相近的項(xiàng)目時(shí),你以前的抽象層說(shuō)不定還可以再次利用 。面對(duì)對(duì)象的設(shè)計(jì),復(fù)用的重點(diǎn)其實(shí)應(yīng)該是抽象層的復(fù)用,而不是具體某一個(gè)代碼塊的復(fù)用。
說(shuō)到了抽象,我就不能不提到曾讓我頭痛的Java接口和Java抽象類(lèi)了,這也是本文我想說(shuō)的重點(diǎn)。
既然面向?qū)ο笤O(shè)計(jì)的重點(diǎn)在于抽象,那Java接口和Java抽象類(lèi)就有它存在的必然性了。
Java接口(interface)和Java抽象類(lèi)(abstract class)代表的就是抽象類(lèi)型,就是我們需要提出的抽象層的具體表現(xiàn)。OOP面向?qū)ο蟮木幊蹋绻岣叱绦虻膹?fù)用率,增加程序 的可維護(hù)性,可擴(kuò)展性,就必須是面向接口的編程,面向抽象的編程,正確地使用接口、抽象類(lèi)這些有用的抽象類(lèi)型作為你結(jié)構(gòu)層次上的頂層。
Java接口和Java抽象類(lèi)有太多相似的地方,又有太多特別的地方,究竟在什么地方,才是它們的最佳位置呢?把它們比較一下,你就可以發(fā)現(xiàn)了。
- Java接口和Java抽象類(lèi)最大的一個(gè)區(qū)別,就在于Java抽象類(lèi)可以提供某些方法的部分實(shí)現(xiàn),而Java接口不可以(就是interface中只能定義方法,而不能有方法的實(shí)現(xiàn),而在abstract class中則可以既有方法的具體實(shí)現(xiàn),又有沒(méi)有具體實(shí)現(xiàn)的抽象方法),這大概就是Java抽象類(lèi)唯一的優(yōu)點(diǎn)吧,但這個(gè)優(yōu)點(diǎn)非常有用。如果向一個(gè)抽象類(lèi)里加入一個(gè)新的具體方法時(shí),那么它所有的子類(lèi)都一下子都得到了這個(gè)新方法,而Java接口做不到這一點(diǎn),如果向一個(gè)Java接口里加入一個(gè) 新方法,所有實(shí)現(xiàn)這個(gè)接口的類(lèi)就無(wú)法成功通過(guò)編譯了,因?yàn)槟惚仨氉屆恳粋€(gè)類(lèi)都再實(shí)現(xiàn)這個(gè)方法才行,這顯然是Java接口的缺點(diǎn)。這個(gè)在我的另外一篇博客mapreduce 新舊API 區(qū)別中有提到類(lèi)似的問(wèn)題,在新的mapreduce api中更傾向于使用抽象類(lèi),而不是接口,因?yàn)檫@更容易擴(kuò)展。原因就是上面劃線部分所說(shuō)的。
- 一個(gè)抽象類(lèi)的實(shí)現(xiàn)只能由這個(gè)抽象類(lèi)的子類(lèi)給出,也就是說(shuō),這個(gè)實(shí)現(xiàn)處在抽象類(lèi)所定義出的繼承的等級(jí)結(jié)構(gòu)中,而由于Java語(yǔ)言的單繼承性,所以抽象類(lèi)作為類(lèi)型定義工具的效能大打折扣。在這一點(diǎn)上,Java接口的優(yōu)勢(shì)就出來(lái)了,任何一個(gè)實(shí)現(xiàn)了一個(gè)Java接口所規(guī)定的方法的類(lèi)都可以具有這個(gè)接口的類(lèi)型,而一個(gè)類(lèi)可以實(shí)現(xiàn)任意多個(gè)Java接口,從而這個(gè)類(lèi)就有了多種類(lèi)型。(使用抽象類(lèi),那么繼承這個(gè)抽象類(lèi)的子類(lèi)類(lèi)型就比較單一,因?yàn)樽宇?lèi)只能單繼承抽象類(lèi);而子類(lèi)能夠同時(shí)實(shí)現(xiàn)多個(gè)接口,因?yàn)轭?lèi)型就比較多。接口和抽象類(lèi)都可以定義對(duì)象,但是只能用他們的具體實(shí)現(xiàn)類(lèi)來(lái)進(jìn)行實(shí)例化。)
- 從第2點(diǎn)不難看出,Java接口是定義混合類(lèi)型的理想工具,混合類(lèi)表明一個(gè)類(lèi)不僅僅具有某個(gè)主類(lèi)型的行為,而且具有其他的次要行為。
- 結(jié)合1、2點(diǎn)中抽象類(lèi)和Java接口的各自優(yōu)勢(shì),具精典的設(shè)計(jì)模式就出來(lái)了:聲明類(lèi)型的工作仍然由Java接口承擔(dān),但是同時(shí)給出一個(gè)Java 抽象類(lèi),且實(shí)現(xiàn)了這個(gè)接口,而其他同屬于這個(gè)抽象類(lèi)型的具體類(lèi)可以選擇實(shí)現(xiàn)這個(gè)Java接口,也可以選擇繼承這個(gè)抽象類(lèi),也就是說(shuō)在層次結(jié)構(gòu)中,Java 接口在最上面,然后緊跟著抽象類(lèi),這下兩個(gè)的最大優(yōu)點(diǎn)都能發(fā)揮到極至了。這個(gè)模式就是“缺省適配模式”。在Java語(yǔ)言API中用了這種模式,而且全都遵循一定的命名規(guī)范:Abstract +接口名。(A extends AbstractB implements interfaceC,那么A即可以選擇實(shí)現(xiàn)(@Override)接口interfaceC中的方法,也可以選擇不實(shí)現(xiàn);A即可以選擇實(shí)現(xiàn)(@Override)抽象類(lèi)AbstractB中的方法,也可以選擇不實(shí)現(xiàn))
Java接口和Java抽象類(lèi)的存在就是為了用于具體類(lèi)的實(shí)現(xiàn)和繼承的,如果你準(zhǔn)備寫(xiě)一個(gè)具體類(lèi)去繼承另一個(gè)具體類(lèi)的話,那你的設(shè)計(jì)就有很大問(wèn)題了。Java抽象類(lèi)就是為了繼承而存在的,它的抽象方法就是為了強(qiáng)制子類(lèi)必須去實(shí)現(xiàn)的。
使用Java接口和抽象Java類(lèi)進(jìn)行變量的類(lèi)型聲明、參數(shù)是類(lèi)型聲明、方法的返還類(lèi)型說(shuō)明,以及數(shù)據(jù)類(lèi)型的轉(zhuǎn)換等。而不要用具體Java類(lèi)進(jìn)行變量的類(lèi)型聲明、參數(shù)是類(lèi)型聲明、方法的返還類(lèi)型說(shuō)明,以及數(shù)據(jù)類(lèi)型的轉(zhuǎn)換等。
2.實(shí)例
下面給出一個(gè)具體的接口Action,代碼如下所示:
- package org.springframework.webflow.execution;
- public interface Action {
- public Event execute(RequestContext context) throws Exception;
- }
在這個(gè)接口中,定義了一個(gè)沒(méi)有具體實(shí)現(xiàn)的方法,方法名叫做execute(),返回類(lèi)型是Event。如前面第一條所述,接口中的方法都是沒(méi)有實(shí)現(xiàn)的。這些方法的具體實(shí)現(xiàn)是在實(shí)現(xiàn)(implements)這個(gè)接口的類(lèi)中給出的。再來(lái)看一個(gè)實(shí)現(xiàn)Action接口的抽象類(lèi)AbstractAction,代碼如下。
- package org.springframework.webflow.action;
-
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.beans.factory.BeanInitializationException;
- import org.springframework.beans.factory.InitializingBean;
- import org.springframework.util.ClassUtils;
- import org.springframework.webflow.core.collection.AttributeMap;
- import org.springframework.webflow.execution.Action;
- import org.springframework.webflow.execution.Event;
- import org.springframework.webflow.execution.RequestContext;
-
- public abstract class AbstractAction implements Action, InitializingBean {
-
- protected final Log logger = LogFactory.getLog(getClass());
-
- public EventFactorySupport getEventFactorySupport() {
- return new EventFactorySupport();
- }
-
- public void afterPropertiesSet() throws Exception {
- try {
- initAction();
- } catch (Exception ex) {
- throw new BeanInitializationException("Initialization of this Action failed: " + ex.getMessage(), ex);
- }
- }
-
- protected void initAction() throws Exception {
- }
-
- protected Event success() {
- return getEventFactorySupport().success(this);
- }
-
- protected Event success(Object result) {
- return getEventFactorySupport().success(this, result);
- }
-
- protected Event error() {
- return getEventFactorySupport().error(this);
- }
-
- protected Event error(Exception e) {
- return getEventFactorySupport().error(this, e);
- }
-
- protected Event yes() {
- return getEventFactorySupport().yes(this);
- }
-
- protected Event no() {
- return getEventFactorySupport().no(this);
- }
-
- protected Event result(boolean booleanResult) {
- return getEventFactorySupport().event(this, booleanResult);
- }
-
- protected Event result(String eventId) {
- return getEventFactorySupport().event(this, eventId);
- }
-
- protected Event result(String eventId, AttributeMap resultAttributes) {
- return getEventFactorySupport().event(this, eventId, resultAttributes);
- }
-
- protected Event result(String eventId, String resultAttributeName, Object resultAttributeValue) {
- return getEventFactorySupport().event(this, eventId, resultAttributeName, resultAttributeValue);
- }
-
- public final Event execute(RequestContext context) throws Exception {
- Event result = doPreExecute(context);
- if (result == null) {
- result = doExecute(context);
- doPostExecute(context);
- } else {
- if (logger.isInfoEnabled()) {
- logger.info("Action execution disallowed; pre-execution result is '" + result.getId() + "'");
- }
- }
- return result;
- }
-
- protected String getActionNameForLogging() {
- return ClassUtils.getShortName(getClass());
- }
-
- protected Event doPreExecute(RequestContext context) throws Exception {
- return null;
- }
-
- //抽象方法
- protected abstract Event doExecute(RequestContext context) throws Exception;
-
- protected void doPostExecute(RequestContext context) throws Exception {
- }
- }
在抽象類(lèi)AbstractAction中,既有具體實(shí)現(xiàn)的方法,又有沒(méi)有具體實(shí)現(xiàn)的抽象方法- //抽象方法
- protected abstract Event doExecute(RequestContext context) throws Exception;
需要注意的是在抽象類(lèi)中,如果方法沒(méi)有具體實(shí)現(xiàn)(就是方法后面沒(méi)有{}),那么必須加上abstract來(lái)聲明這個(gè)方法,而接口中不需要使用abstract來(lái)聲明(抽象類(lèi)之所以被稱(chēng)為抽象類(lèi),就是因?yàn)樗谐橄蠓椒ā:谐橄蠓椒ǖ念?lèi)叫做抽象類(lèi))。
最近突然發(fā)現(xiàn)忘了
數(shù)據(jù)庫(kù)鎖和數(shù)據(jù)庫(kù)隔離級(jí)別,時(shí)常弄混它們之間的關(guān)系。為此特此寫(xiě)下此博客,以方便自己復(fù)習(xí),同時(shí)也可以幫助博友。
數(shù)據(jù)庫(kù)鎖
數(shù)據(jù)庫(kù)鎖就是事務(wù)T在對(duì)某個(gè)數(shù)據(jù)對(duì)象(例如表、記錄等)操作之前,先向系統(tǒng)發(fā)出請(qǐng)求,對(duì)其加鎖。加鎖后事務(wù)T就對(duì)該數(shù)據(jù)對(duì)象有了一定的控制,在事務(wù)T釋放它的鎖之前,其它的事務(wù)不能更新此數(shù)據(jù)對(duì)象。
數(shù)據(jù)庫(kù)鎖是實(shí)現(xiàn)并發(fā)控制的重要技術(shù),但是“鎖”會(huì)帶來(lái)系統(tǒng)額外的開(kāi)銷(xiāo)。所以需要注意選擇封鎖粒度時(shí)必須同時(shí)考慮開(kāi)銷(xiāo)和并發(fā)度兩個(gè)因素,進(jìn)行權(quán)衡,以求得最優(yōu)的效果。
鎖的類(lèi)型主要有兩種類(lèi)型排它鎖(也叫獨(dú)占鎖)和共享鎖,當(dāng)然還有很多教程增加了一種--更新鎖。
共享(S)鎖:多個(gè)事務(wù)可封鎖一個(gè)共享頁(yè);任何事務(wù)都不能修改該頁(yè); 通常是該頁(yè)被讀取完畢,S鎖立即被釋放。在執(zhí)行select語(yǔ)句的時(shí)候需要給操作對(duì)象(表或者一些記錄)加上共享鎖,但加鎖之前需要檢查是否有排他鎖,如果沒(méi)有,則可以加共享鎖(一個(gè)對(duì)象上可以加n個(gè)共享鎖),否則不行。共享鎖通常在執(zhí)行完select語(yǔ)句之后被釋放,當(dāng)然也有可能是在事務(wù)結(jié)束(包括正常結(jié)束和異常結(jié)束)的時(shí)候被釋放,主要取決與數(shù)據(jù)庫(kù)所設(shè)置的事務(wù)隔離級(jí)別。
排它(X)鎖:僅允許一個(gè)事務(wù)封鎖此頁(yè);其他任何事務(wù)必須等到X鎖被釋放才能對(duì)該頁(yè)進(jìn)行訪問(wèn);X鎖一直到事務(wù)結(jié)束才能被釋放。執(zhí)行insert、update、delete語(yǔ)句的時(shí)候需要給操作的對(duì)象加排他鎖(我感覺(jué)在執(zhí)行insert的時(shí)候應(yīng)該是在表級(jí)加排他鎖),在加排他鎖之前必須確認(rèn)該對(duì)象上沒(méi)有其他任何鎖,一旦加上排他鎖之后,就不能再給這個(gè)對(duì)象加其他任何鎖。排他鎖的釋放通常是在事務(wù)結(jié)束的時(shí)候(當(dāng)然也有例外,就是在數(shù)據(jù)庫(kù)事務(wù)隔離級(jí)別被設(shè)置成Read Uncommitted(讀未提交數(shù)據(jù))的時(shí)候,這種情況下排他鎖會(huì)在執(zhí)行完更新操作之后就釋放,而不是在事務(wù)結(jié)束的時(shí)候)。
更新(U)鎖:用來(lái)預(yù)定要對(duì)此頁(yè)施加X(jué)鎖,它允許其他事務(wù)讀,但不允許再施加U鎖或X鎖;當(dāng)被讀取的頁(yè)將要被更新時(shí),則升級(jí)為X鎖;U鎖一直到事務(wù)結(jié)束時(shí)才能被釋放。數(shù)據(jù)庫(kù)是支持在一個(gè)事務(wù)中進(jìn)行自動(dòng)鎖升級(jí)的,例如,在某個(gè)事務(wù)中先執(zhí)行select語(yǔ)句,后執(zhí)行update語(yǔ)句,這兩條語(yǔ)句操作了同一個(gè)對(duì)象,并且假定共享鎖是在事務(wù)結(jié)束的時(shí)候被釋放的。如果數(shù)據(jù)庫(kù)不支持自動(dòng)鎖升級(jí),那么當(dāng)update語(yǔ)句請(qǐng)求排他鎖的時(shí)候?qū)⒉荒艹晒ΑR驗(yàn)橹皊elect語(yǔ)句的共享鎖沒(méi)有被釋放,那么事務(wù)就進(jìn)入了無(wú)限等待,即死鎖。有了自動(dòng)鎖升級(jí),在執(zhí)行update語(yǔ)句的時(shí)候就可以將之前加的共享鎖升級(jí)為排他鎖,但有個(gè)前提,就是這個(gè)共享鎖必須是本事務(wù)自己加的,而且在操作對(duì)象上沒(méi)有在加其他任何鎖,否則共享鎖是不能被升級(jí)為排他鎖的,必須等待其他鎖的釋放。
因?yàn)橥ǔT趫?zhí)行更新操作的時(shí)候要先查詢,也就是我們通常會(huì)在update語(yǔ)句和delete語(yǔ)句中加where子句。那么,有的數(shù)據(jù)庫(kù)系統(tǒng)可能會(huì)在執(zhí)行查詢的時(shí)候先給操作對(duì)象加共享鎖,然后在更新的時(shí)候加排他鎖,但這么做會(huì)有問(wèn)題,也就是如果兩個(gè)事務(wù)同時(shí)要更新一個(gè)對(duì)象,都先給這個(gè)對(duì)象加了共享鎖,當(dāng)要更新的時(shí)候,都請(qǐng)求升級(jí)鎖,但由于這個(gè)對(duì)象上存在對(duì)方事務(wù)加的共享鎖。。所以無(wú)法升級(jí)。這樣兩個(gè)事務(wù)就在等待對(duì)方釋放共享鎖,進(jìn)入死鎖狀態(tài)。更新鎖就是為了解決這個(gè)問(wèn)題,即在執(zhí)行查詢操作的時(shí)候加的不是共享鎖而是更新鎖(一個(gè)對(duì)象上只能有一個(gè)更新鎖和n個(gè)共享鎖),當(dāng)要更新的時(shí)候,再將更新鎖升級(jí)為排他鎖,升級(jí)前提是這個(gè)對(duì)象上只有本事務(wù)加的更新鎖,沒(méi)有其他任何鎖了。其實(shí),,我想,如果在執(zhí)行查詢的時(shí)候就給事務(wù)加排他鎖不也能解決死鎖問(wèn)題嗎,但這樣似乎會(huì)減弱系統(tǒng)的并發(fā)性能。
數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別
在數(shù)據(jù)庫(kù)操作中,為了有效保證并發(fā)讀取數(shù)據(jù)的正確性,提出的事務(wù)隔離級(jí)別。
在沒(méi)有數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別時(shí)會(huì)出現(xiàn)如下問(wèn)題:
更新丟失
兩個(gè)事務(wù)都同時(shí)更新一行數(shù)據(jù),但是第二個(gè)事務(wù)卻中途失敗退出,導(dǎo)致對(duì)數(shù)據(jù)的兩個(gè)修改都失效了。這是因?yàn)橄到y(tǒng)沒(méi)有執(zhí)行任何的鎖操作,因此并發(fā)事務(wù)并沒(méi)有被隔離開(kāi)來(lái)。
臟讀
一個(gè)事務(wù)開(kāi)始讀取了某行數(shù)據(jù),但是另外一個(gè)事務(wù)已經(jīng)更新了此數(shù)據(jù)但沒(méi)有能夠及時(shí)提交。這是相當(dāng)危險(xiǎn)的,因?yàn)楹芸赡芩械牟僮鞫急换貪L。
不可重復(fù)讀
不可重復(fù)讀(Non-repeatable Reads):一個(gè)事務(wù)對(duì)同一行數(shù)據(jù)重復(fù)讀取兩次,但是卻得到了不同的結(jié)果。
包括以下情況:
(1) 事務(wù)T1讀取某一數(shù)據(jù)后,事務(wù)T2對(duì)其做了修改,當(dāng)事務(wù)T1再次讀該數(shù)據(jù)時(shí)得到與前一次不同的值。
(2) 幻讀(Phantom Reads):事務(wù)在操作過(guò)程中進(jìn)行兩次查詢,第二次查詢的結(jié)果包含了第一次查詢中未出現(xiàn)的數(shù)據(jù)或者缺少了第一次查詢中出現(xiàn)的數(shù)據(jù)(這里并不要求兩次查詢的SQL語(yǔ)句相同)。這是因?yàn)樵趦纱尾樵冞^(guò)程中有另外一個(gè)事務(wù)插入數(shù)據(jù)造成的。
為了避免上面出現(xiàn)的幾種情況,在標(biāo)準(zhǔn)SQL規(guī)范中,定義了4個(gè)事務(wù)隔離級(jí)別,不同的隔離級(jí)別對(duì)事務(wù)的處理不同。
未授權(quán)讀取
也稱(chēng)為讀未提交(Read Uncommitted):允許臟讀取,但不允許更新丟失。如果一個(gè)事務(wù)已經(jīng)開(kāi)始寫(xiě)數(shù)據(jù),則另外一個(gè)事務(wù)則不允許同時(shí)進(jìn)行寫(xiě)操作,但允許其他事務(wù)讀此行數(shù)據(jù)。該隔離級(jí)別可以通過(guò)“排他寫(xiě)鎖”實(shí)現(xiàn)。
授權(quán)讀取
也稱(chēng)為讀提交(Read Committed):允許不可重復(fù)讀取,但不允許臟讀取。這可以通過(guò)“瞬間共享讀鎖”和“排他寫(xiě)鎖”實(shí)現(xiàn)。讀取數(shù)據(jù)的事務(wù)允許其他事務(wù)繼續(xù)訪問(wèn)該行數(shù)據(jù),但是未提交的寫(xiě)事務(wù)將會(huì)禁止其他事務(wù)訪問(wèn)該行。
可重復(fù)讀取(Repeatable Read)
可重復(fù)讀取(Repeatable Read):禁止不可重復(fù)讀取和臟讀取,但是有時(shí)可能出現(xiàn)幻影數(shù)據(jù)。這可以通過(guò)“共享讀鎖”和“排他寫(xiě)鎖”實(shí)現(xiàn)。讀取數(shù)據(jù)的事務(wù)將會(huì)禁止寫(xiě)事務(wù)(但允許讀事務(wù)),寫(xiě)事務(wù)則禁止任何其他事務(wù)。
序列化(Serializable)
序列化(Serializable):提供嚴(yán)格的事務(wù)隔離。它要求事務(wù)序列化執(zhí)行,事務(wù)只能一個(gè)接著一個(gè)地執(zhí)行,但不能并發(fā)執(zhí)行。如果僅僅通過(guò)“行級(jí)鎖”是無(wú)法實(shí)現(xiàn)事務(wù)序列化的,必須通過(guò)其他機(jī)制保證新插入的數(shù)據(jù)不會(huì)被剛執(zhí)行查詢操作的事務(wù)訪問(wèn)到。
隔離級(jí)別越高,越能保證數(shù)據(jù)的完整性和一致性,但是對(duì)并發(fā)性能的影響也越大。對(duì)于多數(shù)應(yīng)用程序,可以優(yōu)先考慮把數(shù)據(jù)庫(kù)系統(tǒng)的隔離級(jí)別設(shè)為Read Committed。它能夠避免臟讀取,而且具有較好的并發(fā)性能。盡管它會(huì)導(dǎo)致不可重復(fù)讀、虛讀和第二類(lèi)丟失更新這些并發(fā)問(wèn)題,在可能出現(xiàn)這類(lèi)問(wèn)題的個(gè)別場(chǎng)合,可以由應(yīng)用程序采用悲觀鎖或樂(lè)觀鎖來(lái)控制。
1.前言
作為現(xiàn)在App里必不可少的用戶分享需要,社交化分享顯然是我們開(kāi)發(fā)app里較為常用的。
最近因?yàn)楣続pp有社交化分享的需要,就特此研究了會(huì),拿出來(lái)與大家分享。
想要集成社交會(huì)分享,我們可以使用
ShareSDK - 優(yōu)點(diǎn)功能豐富,缺點(diǎn)體積較大
百度分享SDK - 缺點(diǎn)功能相對(duì)ShareSDK較少,優(yōu)點(diǎn)體積較小
這是現(xiàn)在較為常用的兩種社交化分享工具。
使用哪一種,就看個(gè)人的app的需要來(lái)決定了。
今天我主要說(shuō)的是ShareSDK的簡(jiǎn)單集成和使用。
2.1. 拿自己的Appkey 去下載ShareSDK
下載地址:http://sharesdk.cn/Download
2.2. 申請(qǐng)分享工具的Appkey
例如: 新浪微博、
騰訊微博、豆瓣應(yīng)用、人人網(wǎng)、QQ空間
去各大社交網(wǎng)站的開(kāi)發(fā)者平臺(tái),進(jìn)行注冊(cè)申請(qǐng)即可。
獲取如下:
//新浪微博:
//App Key:2258477553
//App Secret:1e2f275afc375109e456f550fb3918e8
//騰訊微博:
//App key:2620460989
//App secret:58c55f572d5ae35e0c355f4c0ee11283
3.集成ShareSDK
3.1.注冊(cè)使用ShareSDK
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//注冊(cè)ShareSDK
[ShareSDK registerApp:@"1983bf0916db”];
return YES;
}
3.2.添加要集成的分享平臺(tái)
注意: 新浪微博需要提供回調(diào)地址才行
回調(diào)地址去新浪開(kāi)發(fā)者平臺(tái)獲取
如圖:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //注冊(cè)ShareSDK [ShareSDK registerApp:@"1983bf0916db”]; //添加新浪微博應(yīng)用 [ShareSDK connectSinaWeiboWithAppKey:@"2620460989" appSecret:@"58c55f572d5ae35e0c355f4c0ee11283" redirectUri:@"http://weibo.cn/ext/share?ru=http%3A%2F%2F16kxs.com%2Fwap%2FBook%2FShow.aspx%3Fid%3D7983%26lmid%3D0%26uid%3D0%26ups%3D0&rt=%E9%83%BD%E5%B8%82%E7%89%A7%E9%AC%BC%E4%BA%BA&st=1301645308&appkey=2620460989”]; //添加騰訊微博應(yīng)用 [ShareSDK connectTencentWeiboWithAppKey:@"801307650" appSecret:@"ae36f4ee3946e1cbb98d6965b0b2ff5c" redirectUri:@"http://www.sharesdk.cn"]; //添加豆瓣應(yīng)用 [ShareSDK connectDoubanWithAppKey:@"07d08fbfc1210e931771af3f43632bb9" appSecret:@"e32896161e72be91" redirectUri:@"http://dev.kumoway.com/braininference/infos.php"]; //添加人人網(wǎng)應(yīng)用 [ShareSDK connectRenRenWithAppKey:@"fc5b8aed373c4c27a05b712acba0f8c3" appSecret:@"f29df781abdd4f49beca5a2194676ca4"]; //添加Facebook應(yīng)用 [ShareSDK connectFacebookWithAppKey:@"107704292745179" appSecret:@"38053202e1a5fe26c80c753071f0b573"]; } |
3.3.彈出分享View
a.初始化默認(rèn)分享內(nèi)容
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"123" ofType:@"png"]; //構(gòu)建優(yōu)秀的SDK //構(gòu)造分享內(nèi)容 id<ISSContent> publishContent = [ShareSDK content:@"iOS社交化分享測(cè)試內(nèi)容。" defaultContent:@"默認(rèn)分享內(nèi)容,沒(méi)內(nèi)容時(shí)顯示" image:[ShareSDK imageWithPath:imagePath] title:@"ShareSDK" url:@"http://www.sharesdk.cn" description:@"這是一條測(cè)試信息" mediaType:SSPublishContentMediaTypeNews]; |
b.彈出分享View
[ShareSDK showShareActionSheet:nil shareList:nil content:publishContent statusBarTips:YES authOptions:nil shareOptions: nil result:^(ShareType type, SSResponseState state, id<ISSPlatformShareInfo> statusInfo, id<ICMErrorInfo> error, BOOL end) { if (state == SSResponseStateSuccess) { NSLog(@"分享成功"); } else if (state == SSResponseStateFail) { NSLog(@"分享失敗,錯(cuò)誤碼:%d,錯(cuò)誤描述:%@", [error errorCode], [error errorDescription]); } }]; |
效果圖:
對(duì)于
JAVA中變量的初始化是一個(gè)很基礎(chǔ)的問(wèn)題,其中的一些問(wèn)題也是易被
學(xué)習(xí)者所忽略。當(dāng)在編寫(xiě)代碼的時(shí)候碰到時(shí),常被這些問(wèn)題引發(fā)的錯(cuò)誤,感覺(jué)莫名其妙。而且現(xiàn)在許多大公司的
面試題,對(duì)于這方面的考查也是屢試不爽。以下是對(duì)java變量初始化的時(shí)機(jī)的分析。
【java變量執(zhí)行初始化的步驟】
java是一門(mén)強(qiáng)類(lèi)型語(yǔ)言,因此java語(yǔ)言規(guī)定每個(gè)變量必須先聲明,然后才能使用,聲明變量時(shí)必須指定該變量的數(shù)據(jù)類(lèi)型。首先看下面這條語(yǔ)句的執(zhí)行過(guò)程:
int a = 5;
實(shí)際上面這條語(yǔ)句會(huì)被拆分成兩個(gè)過(guò)程執(zhí)行:
(1)int a ;//創(chuàng)建java對(duì)象時(shí)根據(jù)該語(yǔ)句為變量分配內(nèi)存空間;
(2)a = 5;//賦值操作會(huì)最終被提取到構(gòu)造器中執(zhí)行初始化操作。
實(shí)際上在java中,在使用new操作符創(chuàng)建一個(gè)類(lèi)的實(shí)例對(duì)象的時(shí)候,開(kāi)始分配空間并將成員變量初始化為默認(rèn)的數(shù)值,在這里并不是指將變量初始化為在變量定義處的初始值,對(duì)于基本類(lèi)型變量,默認(rèn)值空值是0或false,對(duì)于引用類(lèi)型變量,默認(rèn)空值為null。這一切都是在構(gòu)造函數(shù)執(zhí)行之前,變量的真正初始化是在構(gòu)造函數(shù)中執(zhí)行。
【java中變量初始化的時(shí)機(jī)】
1、程序可以在3個(gè)地方對(duì)實(shí)例變量進(jìn)行初始化:
(1)定義實(shí)例變量的時(shí)候指定初始值;
(2)非靜態(tài)初始化代碼塊中對(duì)實(shí)例變量指定初值;
(3)構(gòu)造器中對(duì)實(shí)例變量指定初值。
雖然程序在3個(gè)地方都可對(duì)實(shí)例變量指定初始值,但(1)、(2)處的賦值操作最終會(huì)被提取到構(gòu)造器中執(zhí)行。且(1)、(2)的執(zhí)行順序與他們?cè)谠闯绦蛑谐霈F(xiàn)的順序相同。可以通過(guò)JDK的javap工具來(lái)看程序的執(zhí)行過(guò)程:
2、java中類(lèi)變量初始化的時(shí)機(jī):
(1)定義類(lèi)變量的時(shí)候指定初始值;
(2)靜態(tài)初始化代碼塊中對(duì)類(lèi)變量指定初值。
這里類(lèi)變量初始化的時(shí)機(jī)為兩處,而沒(méi)有在構(gòu)造器中這一說(shuō)。這也很容易理解,因?yàn)轭?lèi)變量是類(lèi)加載的時(shí)候執(zhí)行的初始化,且只執(zhí)行一次,而調(diào)用構(gòu)造器是對(duì)象實(shí)例化執(zhí)行的,每實(shí)例化一次對(duì)象,執(zhí)行一次。
第一個(gè)正式的universal項(xiàng)目差不多快要結(jié)束,總結(jié)一下,分享給大家。因?yàn)榭赡芪业谋容^具有代表性,如何從壓根不懂開(kāi)始做起。(分享的另外一個(gè)目的也是希望大家提提建議,畢竟只有互相交流中才能更快成長(zhǎng))
-----------------------------------------------
做項(xiàng)目前:
零面向?qū)ο髮?shí)際項(xiàng)目經(jīng)驗(yàn),更不用說(shuō)透徹理解design pattern
零iOS實(shí)際項(xiàng)目經(jīng)驗(yàn)
只懂一點(diǎn)點(diǎn)的C和匯編代碼,其它如
java、ruby、php、HTML5一點(diǎn)不沾邊,可以說(shuō)是不屬于
互聯(lián)網(wǎng)的業(yè)余玩家
項(xiàng)目的情況:
做項(xiàng)目過(guò)程中,客戶需求變化極其頻繁和巨大,對(duì)代碼結(jié)構(gòu)的robust是一大挑戰(zhàn)。雖然本人特別討厭需求變動(dòng),但是在外,身不由己
Universal項(xiàng)目,即是iPhone + iPad 的一個(gè)項(xiàng)目
基本上這個(gè)項(xiàng)目涉及到了iOS的方方面面,麻雀雖小,但是五臟俱全
關(guān)于程序結(jié)構(gòu)設(shè)計(jì)
嘗試用面向?qū)ο蟮姆绞饺ピO(shè)計(jì)結(jié)構(gòu),但設(shè)計(jì)的時(shí)候流于形式,根據(jù)現(xiàn)有的一些best practice依葫蘆畫(huà)瓢,但實(shí)際上只有實(shí)踐了才知道,比如:
1. 屬性: 什么時(shí)候用和為什么用屬性、如何保持屬性私有、self.的使用,屬性的內(nèi)存釋放;
2. 成員變量和屬性的區(qū)別
3. 方法:什么時(shí)候用類(lèi)方法和對(duì)象方法
4. 好的設(shè)計(jì)真的是“增之一分則太長(zhǎng),減之一分則太短”;好的設(shè)計(jì)關(guān)系到以后重構(gòu)的方便性
5. 解耦設(shè)計(jì):對(duì)象之間如何通訊,如何傳值,如何回傳,如何用好notification、delegate、KVO;如何保持對(duì)象的純潔(不受玷污)
6. MVC中的M和C分離,一直覺(jué)得自己做的項(xiàng)目是小項(xiàng)目,而且一直認(rèn)為過(guò)于注重結(jié)構(gòu),會(huì)增加代碼量,但是實(shí)際上項(xiàng)目不分大小,好的設(shè)計(jì):
能隨時(shí)應(yīng)對(duì)客戶的需求變化
能自己看得懂自己寫(xiě)的代碼(改的多了,都看不懂自己的代碼了,這是最悲催)
回歸
測(cè)試,一旦客戶需求改變,亂糟糟的代碼更加亂,這樣回歸基本上是需要全部。好的設(shè)計(jì)可以把客戶需求改變帶來(lái)的回歸測(cè)試降低到最低
關(guān)于面向?qū)ο笤O(shè)計(jì)
之前從沒(méi)有面向?qū)ο笤O(shè)計(jì)的經(jīng)驗(yàn),所以第一次從這種角度去解決問(wèn)題。“實(shí)踐出真理”,無(wú)論你平時(shí)看多少書(shū),如果沒(méi)有實(shí)踐過(guò),真的是無(wú)法體會(huì)面向?qū)ο笤O(shè)計(jì)的:
一切從面向?qū)ο蟪霭l(fā)設(shè)計(jì):類(lèi)、對(duì)象、(私有)方法、(私有)屬性
所謂面向?qū)ο螅褪歉鶕?jù)現(xiàn)實(shí)世界中客觀存在的事物(即對(duì)象)出發(fā)來(lái)構(gòu)造軟件系統(tǒng)
只有真正從面向?qū)ο笕ピO(shè)計(jì),幾個(gè)月甚至幾年后,你才能復(fù)盤(pán)你的代碼。以前一直覺(jué)得代碼復(fù)盤(pán)如同圍棋復(fù)盤(pán)絕對(duì)是天才才有的本領(lǐng),現(xiàn)在才明白,其實(shí)關(guān)鍵是:你要清楚的知道你的代碼用在了哪里,為什么用
從面向?qū)ο蟪霭l(fā),不要覺(jué)得一個(gè)功能很簡(jiǎn)單一個(gè)方法就搞定,盡量用面向?qū)ο笕タ紤]。這是做項(xiàng)目過(guò)程中犯的最大的錯(cuò)誤
關(guān)于ARC
我是項(xiàng)目做了1個(gè)月后,才決定把項(xiàng)目從MRC轉(zhuǎn)到ARC,現(xiàn)在回頭看看,當(dāng)初真實(shí)明智,因?yàn)樵诘谝粋€(gè)月,內(nèi)存管理上的問(wèn)題和處理讓我很頭疼也很花時(shí)間。關(guān)于ARC
沒(méi)有想象中的會(huì)比MRC性能差,ARC不是JAVA的垃圾回收,性能其實(shí)與MRC基本一致
ARC中沒(méi)有明確的release操作,這時(shí)更需要注意內(nèi)存管理,比如在一個(gè)Controller中使用Gyro sensor的時(shí)候,這種操作是絕對(duì)不能賦值給局部變量的:[[CMMotionManager alloc]init]
雖然ARC似乎能為你做很多事,但是有些事情自己解決還是自己解決,比如當(dāng)不需要用Gyro sensor時(shí),_motionManager = nil(此時(shí)如果不設(shè)置,則startDeviceMotionUpdatesToQueue中的更新會(huì)一直進(jìn)行);
總之,對(duì)于ARC,難得糊涂中要“時(shí)刻保持覺(jué)醒”
關(guān)于Perfomrance設(shè)計(jì)
Coding真的是一點(diǎn)都來(lái)不得馬虎,以前一直覺(jué)得iOS性能強(qiáng)大,無(wú)須擔(dān)心性能,但是項(xiàng)目做下來(lái),一大痛苦之處就是性能不夠:
應(yīng)用程序、UIViewController和UIView的生命周期的認(rèn)識(shí)如果不十分清楚,就很容易造成性能瓶頸
大量的UIView插入移除操作會(huì)導(dǎo)致性能問(wèn)題
UITableView和UIScrollView導(dǎo)致滑動(dòng)不順暢的best practice
關(guān)于知識(shí)點(diǎn)
成為一名優(yōu)秀Programmer需要豐富的經(jīng)驗(yàn)和知識(shí)面,但是知識(shí)永遠(yuǎn)是
學(xué)習(xí)不完的,所以要抓核心和基本,個(gè)人覺(jué)得以下幾個(gè)知識(shí)點(diǎn)是iOS開(kāi)發(fā)必須的。至于有些比如CoreText、CoreImage等,其實(shí)等到需要用時(shí)再去學(xué)習(xí)也來(lái)得及。
內(nèi)存管理,MRC和ARC
多線程,iOS下有多種多線程實(shí)現(xiàn)方式,什么都應(yīng)該了解一下,但是除了dispatch需要精通,其它只需要看懂 (dispatch效率最高,使用最方便)
UIViewController、UITableViewController 和應(yīng)用程序的生命周期
看似簡(jiǎn)單但是很有深度的View之間的轉(zhuǎn)場(chǎng)處理,因?yàn)樯婕暗酱罅可芷冢鏿resentModalViewController, presentViewController, pushViewController, addSubview, removeFromSuperview, self.view....
網(wǎng)絡(luò)處理相關(guān)的,如何請(qǐng)求JSON數(shù)據(jù),如何HTTP GET和POST
旋轉(zhuǎn)處理,特別是iOS4、iOS5、iOS6的不同處理
Debug的能力
基本的設(shè)計(jì)模式:MVC、delegate、notification、target-action
面向?qū)ο蟮暮诵乃枷耄纾翰灰杂脩魺o(wú)法使用或不感興趣的東西擾亂類(lèi)的公有接口、類(lèi)之間應(yīng)該零耦合、把不相關(guān)的信息放在另一個(gè)類(lèi)中
不重復(fù)造輪子
這個(gè)也不例外,iOS下的開(kāi)源framework都太多了,基本上你需要的都能在Github或者Stackoverflow上找得到,所以平時(shí):
不要做井底之蛙,平時(shí)多了解開(kāi)源的框架
框架適合就行,就像爭(zhēng)論AFNetwork和ASIHttpNetwork更棒沒(méi)有意義的。寫(xiě)程序的有兩類(lèi)人,一類(lèi)人追求技術(shù)極致,一類(lèi)人技術(shù)只是實(shí)現(xiàn)產(chǎn)品的一種手段,我就是后面這個(gè)
關(guān)于開(kāi)源框架的學(xué)習(xí)
這世界好的開(kāi)源框架太多了,給我10年都看不完,所以需要選擇,就像讀書(shū)不在于都多,而在于讀精,個(gè)人推薦如下。
Three20 (其實(shí)我是不推薦的,因?yàn)樗^(guò)時(shí)了,但是因?yàn)樘詫毧蛻舳擞玫剑?/div>
AFNetwork
MBProgressHUD
SDWebImage
關(guān)于Continuous Improvement
Six sigma中提到了持續(xù)改進(jìn),我們的能力提高也是這樣。通過(guò)讀好的開(kāi)源框架是最好的進(jìn)步方式。如何讀開(kāi)源框架,我們讀開(kāi)源框架的目的:
其中的花式寫(xiě)法我們只是了解,不是我們的目的
了解作者寫(xiě)框架的思路
對(duì)比自己現(xiàn)有的,求改進(jìn)
關(guān)于設(shè)計(jì)模式
做項(xiàng)目前,把GOF的23種設(shè)計(jì)模式都看了一遍,項(xiàng)目做下了,體會(huì)到:
單看設(shè)計(jì)模式的書(shū),純粹是無(wú)用;
設(shè)計(jì)模式的核心在于平時(shí)的有意無(wú)意的使用,因?yàn)樗旧韥?lái)源于實(shí)際;
能熟背23種設(shè)計(jì)模式固然是件好事,但是不能也不見(jiàn)得是壞事(反正我是記不住的)
欲速則不達(dá)
代碼之間往往只查一兩個(gè)字符,但性能和結(jié)局多半千差萬(wàn)別,因?yàn)轫?xiàng)目緊,壓力大,又是第一個(gè)項(xiàng)目,所以寫(xiě)代碼的時(shí)候,追求:"meet requirement,先滿足功能,再考慮代碼結(jié)構(gòu)",但是實(shí)際:
需求無(wú)論大小,代碼結(jié)構(gòu)設(shè)計(jì)是必須的而且是第一位的,因?yàn)檫@關(guān)系到未來(lái)的改動(dòng),未來(lái)自己能否看懂;
欲速則不達(dá),真是一個(gè)真理
關(guān)于Best Practice的重要
iOS已經(jīng)很成熟了,基本上,所有問(wèn)題都能找到答案,所有的需求都有現(xiàn)成的framework,或者只需要稍許改改。但是也正因?yàn)?#8220;萬(wàn)能的internet”,所以很多答案或者很多framework都是有問(wèn)題的,所以適時(shí)總結(jié)很重要:
把常用的代碼或者容易錯(cuò)的代碼寫(xiě)到Xcode的snippet中
要有自己的library,不是自己擺酷,而是知識(shí)需要積累,有些開(kāi)發(fā)中經(jīng)常會(huì)遇到的
用好的framework。不流行的框架要注意是否用了私有方法(蘋(píng)果 will reject it)
best practice,比如如何自定義TableCell,如何自定義Navigation bar
不玩花的,不玩偏門(mén)的,寫(xiě)代碼就是規(guī)規(guī)矩矩,一切按照蘋(píng)果的best practice寫(xiě)
面向?qū)ο蟮乃枷胗泻芏喔乓綍r(shí)要時(shí)刻提醒自己
關(guān)于HTML5
iOS原生與HTML5 WEB APP天生就是一對(duì)敵人,做HTML5的可以不懂iOS開(kāi)發(fā),但是做iOS開(kāi)發(fā)必須懂點(diǎn)HTML5:
iOS應(yīng)用中一些“高度變化”或“性能要求不高”或“上線緊迫”的地方會(huì)用到UIWebView
iOS原生與UIWebView的之間交互其實(shí)也可以很棒,甚至JSP交互
HTML5是“可能”的未來(lái),世界都在談?wù)?/div>
HTML5看似只有一個(gè)知識(shí)點(diǎn),但是其實(shí)要求比iOS原生開(kāi)都高:一個(gè)典型的移動(dòng)HTML5頁(yè)面 = JSP + HTML + CSS + JQuery + backbone.js。或者學(xué)習(xí)PhoneGap也是不錯(cuò)的注意。
關(guān)于未來(lái):
如何讓自己在最短的時(shí)間內(nèi)成為優(yōu)秀,這是每天都在思考的,因?yàn)閷?duì)比別人_大學(xué)+工作下來(lái)的多年工作經(jīng)驗(yàn),我是不懼任何優(yōu)勢(shì)的,但是既然入行,就必須做優(yōu)秀。所以選擇值得做的事尤其重要:
看書(shū)沒(méi)用,實(shí)踐和Coding是提高能力的唯一途徑;
做實(shí)際項(xiàng)目比自己玩玩靠譜十萬(wàn)倍
壓力下工作成長(zhǎng)更快,所以不斷挑戰(zhàn)自己,人的潛力是無(wú)限的
番茄工作法則比較適合我(每次集中做半個(gè)小時(shí))
1. Bugzilla
2. Bugfree
3. TestDirector (Quality Center)
4. ClearQuest
5. JIRA
6. Mantis
7. Bugzero
8. BugTracker
9. URTracker
10.KisTracker
11.TestLink
12、JTrac
13、BugNet
14、BugOnline
15、eTraxis
一、Bugzilla(免費(fèi),跨平臺(tái))
Bugzilla是一開(kāi)源Bug Tracking System,是專(zhuān)門(mén)為Unix定制開(kāi)發(fā)的。但是在windows平臺(tái)下依然可以成功安裝使用.
Testopia是一款和Bugzilla集成到一起的
test case management系統(tǒng).
它的強(qiáng)大功能表現(xiàn)在以下幾個(gè)方面:
1. 強(qiáng)大的檢索功能
2. 用戶可配置的通過(guò)Email公布Bug變更
3. 歷史變更記錄
4. 通過(guò)跟蹤和描述處理Bug
5. 附件管理
6. 完備的產(chǎn)品分類(lèi)方案和細(xì)致的安全策略
7. 安全的審核機(jī)制
10. 友好的網(wǎng)絡(luò)用戶界面
11. 豐富多樣的配置設(shè)定
12. 版本間向下兼容
二、BugFree(免費(fèi))
BugFree是借鑒
微軟的研發(fā)流程和Bug管理理念,使用PHP+MySQL獨(dú)立寫(xiě)出的一個(gè)Bug管理系統(tǒng)。簡(jiǎn)單實(shí)用、免費(fèi)并且開(kāi)放源代碼(遵循GNU GPL)。
三、Quality Center(商業(yè),前身Mercury TestDirector ,跨平臺(tái))
HP Quality Center; 提供了基于 Web 的系統(tǒng),可在廣泛的應(yīng)用環(huán)境下自動(dòng)執(zhí)行軟件質(zhì)量
測(cè)試和管理。儀表盤(pán)技術(shù)使您可以了解驗(yàn)證功能和將業(yè)務(wù)流程自動(dòng)化,并確定生產(chǎn)中阻礙業(yè)務(wù)成果的瓶頸。HP Quality Center 使 IT 團(tuán)隊(duì)能夠在開(kāi)發(fā)流程完成前就參與應(yīng)用程序測(cè)試。這樣將縮短發(fā)布時(shí)間表,同時(shí)確保最高水平的質(zhì)量。
企業(yè)級(jí)的軟件質(zhì)量解決方案。
IBM Rational ClearQuest 是一款強(qiáng)大的軟件開(kāi)發(fā)測(cè)試工具。集成并自動(dòng)化軟件及系統(tǒng)開(kāi)發(fā)的業(yè)務(wù)過(guò)程。V7.0 提供增強(qiáng)的需求跟蹤、構(gòu)建跟蹤、企業(yè)測(cè)試管理,及部署跟蹤的功能。這提供了從開(kāi)發(fā)到部署的完整的審計(jì)跟蹤,并擴(kuò)展了跨生命周期的可追溯性。軟件增強(qiáng)了開(kāi)發(fā)流程并使之自動(dòng)化,同時(shí)還提高了軟件生命周期的可理解性、可預(yù)測(cè)性和可控制性。
五、JIRA(商業(yè))
JIRA是集項(xiàng)目計(jì)劃、任務(wù)分配、
需求管理、錯(cuò)誤跟蹤于一體的商業(yè)軟件。
JIRA功能全面,界面友好,安裝簡(jiǎn)單,配置靈活,權(quán)限管理以及可擴(kuò)展性方面都十分出色。
JIRA創(chuàng)建的默認(rèn)問(wèn)題類(lèi)型包括New Feature、Bug、Task和Improvement四種,還可以自己定義,所以它也一是過(guò)程管理系統(tǒng)。
Jira融合了
項(xiàng)目管理、任務(wù)管理和缺陷管理,許多著名的開(kāi)源項(xiàng)目都采用了JIRA。
JIRA 是目前比較流行的基于Java架構(gòu)的管理系統(tǒng),由于Atlassian公司對(duì)很多開(kāi)源項(xiàng)目實(shí)行免費(fèi)提供缺陷跟蹤服務(wù),因此在開(kāi)源領(lǐng)域,其認(rèn)知度比其他的產(chǎn)品要高得多,而且易用性也好一些。同時(shí),開(kāi)源則是其另一特色,在用戶購(gòu)買(mǎi)其軟件的同時(shí),也就將源代碼也購(gòu)置進(jìn)來(lái),方便做二次開(kāi)發(fā)。
六、Mantis(開(kāi)源)
Mantis是一個(gè)基于PHP技術(shù)的輕量級(jí)的缺陷跟蹤系統(tǒng),其功能與前面提及的JIRA系統(tǒng)類(lèi)似,都是以Web操作的形式提供項(xiàng)目管理及缺陷跟蹤服務(wù)。在功能上可能沒(méi)有JIRA那么專(zhuān)業(yè),界面也沒(méi)有JIRA漂亮,但在實(shí)用性上足以滿足中小型項(xiàng)目的管理及跟蹤。更重要的是其開(kāi)源,不需要負(fù)擔(dān)任何費(fèi)用。不過(guò)目前的版本還存在一些問(wèn)題,期待在今后的版本中能夠得以完善。
七、Bugzero 免費(fèi)開(kāi)源,跨平臺(tái))
BUGZERO? 是一個(gè)多功能,基于網(wǎng)絡(luò) (web-based) 并在瀏覽器 (browser) 下運(yùn)行的 Bug缺陷管理和跟蹤系統(tǒng) (bug tracking system),可用來(lái)記錄,跟蹤,并歸類(lèi)處理軟件開(kāi)發(fā)過(guò)程出現(xiàn)的 Bug 和硬件系統(tǒng)中存在的缺陷(defect)。 BUGZERO 也是一個(gè)完整的服務(wù)管理軟件,包括集成服務(wù)臺(tái)熱線流程管理(Help Desk),可用來(lái)記錄各種日常事務(wù),變更請(qǐng)求,和問(wèn)題報(bào)告,及追蹤和處理各種客戶訊問(wèn),反饋,和意見(jiàn)。
BUGZERO 提供了一個(gè)可靠的中央數(shù)據(jù)庫(kù)使公司內(nèi)部團(tuán)隊(duì)成員以及外部客戶能在任何地點(diǎn)任何時(shí)間進(jìn)行協(xié)調(diào)和信息交流,并且使任何記錄都有據(jù)可查。它使你省時(shí)省力。BUGZERO 不但使用方便,而且功能齊全,變通性好,能夠靈活設(shè)置各種實(shí)際
工作流程,滿足你特定的業(yè)務(wù)和產(chǎn)品環(huán)境下的需求。這種靈活、易用的缺陷跟蹤流程不僅增強(qiáng)了項(xiàng)目開(kāi)發(fā)的質(zhì)量,同時(shí)也提高了整個(gè)機(jī)構(gòu)的生產(chǎn)效率。
八、BugTracker(免費(fèi)開(kāi)源,跨平臺(tái))
Bugtracker是一個(gè)完整的bug/issue管理系統(tǒng).它使用Java Servlet作為web前臺(tái),MySQL數(shù)據(jù)庫(kù)作為后臺(tái)。
九、JTrac(開(kāi)源)
JTrac是一個(gè)開(kāi)源且可高度配置的問(wèn)題追蹤的Web應(yīng)用程序。它是一個(gè)一般性問(wèn)題,跟蹤網(wǎng)絡(luò)應(yīng)用程序,可方便地實(shí)現(xiàn)定制,增加自定義字段和下拉式。其特點(diǎn)包括可定制的工作流程,實(shí)地一級(jí)的權(quán)限,電子郵件集成,文件附件和詳細(xì)的歷史觀點(diǎn)。
十、BugNet(開(kāi)源)
BugNet是一個(gè)不錯(cuò)的開(kāi)源bug跟蹤和項(xiàng)目管理系統(tǒng)
十一、BugOnline(開(kāi)源)
BugOnline 是一個(gè)開(kāi)源的BUG管理系統(tǒng)。其功能強(qiáng)大,易于使用。
基于asp.net2.0 ,sql server 2005(包括Express 版),Ajax等技術(shù).
BugOnline 的一些特性:
在線消息及E-mail自動(dòng)通知功能。有新Bug及Bug分配給用戶同時(shí)將自動(dòng)通知用戶。
優(yōu)秀的人員分配,工作量統(tǒng)計(jì)功能。
居于項(xiàng)目角色的權(quán)限管理,工作規(guī)劃,流程化。
Bug狀態(tài)統(tǒng)計(jì),便于掌控項(xiàng)目進(jìn)度。
基于SSL的數(shù)據(jù)傳輸,確保數(shù)據(jù)不被截取,保證安全性。(也可設(shè)定為非SSL)
強(qiáng)大的報(bào)表功能。
十二、eTraxis(開(kāi)源)
eTraxis是基于網(wǎng)頁(yè)的免費(fèi)bug跟蹤系統(tǒng)。主要特點(diǎn)是:完全自定義模板,先進(jìn)的過(guò)濾器, LDAP支持,電子郵件通知,訂閱報(bào)刊,提醒,靈活的權(quán)限管理,圖形化的項(xiàng)目指標(biāo)等。
十三、URTracker(商業(yè))
URTracker 是一款通用的流程化的問(wèn)題跟蹤管理軟件。它可以:
幫助您集中管理各種類(lèi)型的問(wèn)題、工作任務(wù)、人員交互等事務(wù);
跟蹤每個(gè)事務(wù)的處理過(guò)程;
控制問(wèn)題處理的流程;
提供一個(gè)有效的協(xié)作平臺(tái),簡(jiǎn)化團(tuán)隊(duì)成員的交互,提升溝通效率;
積累知識(shí)信息;
幫助您進(jìn)行統(tǒng)計(jì)和分析;
十四、KisTracker
KisTracker一款bug跟蹤管理軟件(原名叫:iTracker),功能強(qiáng)大,易于使用,是基于WEB方式的協(xié)同工作軟件.
它用于幫助公司和團(tuán)隊(duì)跟蹤工作中的問(wèn)題,管理和記錄這些問(wèn)題的處理過(guò)程.可以應(yīng)用于:
1.產(chǎn)品BUG跟蹤
2.任務(wù)跟蹤
3.服務(wù)跟蹤
4.各種處理問(wèn)題跟蹤
十五、TestLink(開(kāi)源)
TestLink用于進(jìn)行測(cè)試過(guò)程中的管理,通過(guò)使用TestLink提供的功能,
可以將測(cè)試過(guò)程從測(cè)試需求、測(cè)試設(shè)計(jì)、到測(cè)試執(zhí)行完整的管理起來(lái),
同時(shí),它還提供了好多種測(cè)試結(jié)果的統(tǒng)計(jì)和分析,使我們能夠簡(jiǎn)單的開(kāi)始測(cè)試工作和分析測(cè)試結(jié)果。
TestLink 是sourceforge的開(kāi)放源代碼項(xiàng)目之一。作為基于web的測(cè)試管理系統(tǒng),TestLink的主要功能包括:測(cè)試需求管理 測(cè)試用例管理測(cè)試用例對(duì)測(cè)試需求的覆蓋管理 測(cè)試計(jì)劃的制定 測(cè)試用例的執(zhí)行 大量測(cè)試數(shù)據(jù)的度量和統(tǒng)計(jì)功能。
主站蜘蛛池模板:
亚洲a在线视频视频|
亚洲一区二区三区四区视频|
亚洲成av人片在线看片|
产传媒61国产免费|
114级毛片免费观看|
国产一级特黄高清免费大片|
亚洲Av无码专区国产乱码DVD|
亚洲精品自偷自拍无码|
两个人日本WWW免费版|
国产在线观看免费视频播放器|
久久亚洲国产成人精品性色|
免费播放国产性色生活片|
成人黄页网站免费观看大全|
亚洲AV无码久久精品成人|
国产一级淫片a免费播放口|
中国一级特黄的片子免费|
亚洲无线一二三四区手机|
亚洲一区二区三区亚瑟|
在线观看免费高清视频|
亚洲最新视频在线观看|
亚洲精品免费在线视频|
国产成人精品日本亚洲直接|
99免费观看视频|
亚洲中文字幕无码中文字在线|
亚洲精品GV天堂无码男同|
中国人xxxxx69免费视频|
亚洲国产午夜电影在线入口|
日日麻批免费40分钟无码|
亚洲第一页在线播放|
99在线免费观看视频|
亚洲国产精品久久丫|
成人免费无码大片a毛片软件|
亚洲欧洲av综合色无码|
午夜亚洲av永久无码精品|
亚洲另类自拍丝袜第五页|
亚洲电影日韩精品|
午夜亚洲国产精品福利|
国产免费卡一卡三卡乱码|
一级免费黄色大片|
亚洲精品视频在线观看你懂的
|
亚洲欧美日韩一区二区三区
|