關(guān)于士兵殺敵java代碼的信息

求一款手機(jī)單機(jī)游戲的名字,以前在按鍵機(jī)上玩過(guò)的Java游戲,走格子的戰(zhàn)旗回合類,主角是亞瑟王可以造兵

我也正在找這款游戲,同問(wèn),以前在諾基亞上玩過(guò)。不過(guò)最早玩的一個(gè)版本是以隋唐為背景的,主角是唐太宗李世民,步兵弓手術(shù)士(水兵)騎兵槍兵(重步兵)最強(qiáng)是投石機(jī),不同地形對(duì)不同兵種有加成,祭司召喚尸體完全相同,有劇情,最終BOSS也是遠(yuǎn)程打擊。還有自由對(duì)戰(zhàn)模式超好玩的,簡(jiǎn)直就是策略戰(zhàn)棋啟蒙,可是這么多年過(guò)去已經(jīng)找不到了。

創(chuàng)新互聯(lián) - 成都服務(wù)器托管,四川服務(wù)器租用,成都服務(wù)器租用,四川網(wǎng)通托管,綿陽(yáng)服務(wù)器托管,德陽(yáng)服務(wù)器托管,遂寧服務(wù)器托管,綿陽(yáng)服務(wù)器托管,四川云主機(jī),成都云主機(jī),西南云主機(jī),成都服務(wù)器托管,西南服務(wù)器托管,四川/成都大帶寬,機(jī)柜大帶寬,四川老牌IDC服務(wù)商

下圖屬于哪一類設(shè)計(jì)原則

Copyright ? 1999-2020, CSDN.NET, All Rights Reserved

java

打開(kāi)APP

成勝文

關(guān)注

設(shè)計(jì)模式 — 6大設(shè)計(jì)原則(單一職責(zé)和里氏替換原則) 原創(chuàng)

2022-11-04 01:26:20

成勝文

碼齡4年

關(guān)注

6大設(shè)計(jì)原則

說(shuō)明

單一職責(zé)原則

示例 一

示例 二

總結(jié)

里氏替換原則

示例 一

示例 二

示例 三

總結(jié)

說(shuō)明

6大設(shè)計(jì)原則來(lái)自于觀看 “設(shè)計(jì)模式之禪” 一書(shū)后的總結(jié)

單一職責(zé)原則

單一職責(zé)原則的英文名稱是Single Responsibility Principle,簡(jiǎn)稱是SRP。這個(gè)原則存在爭(zhēng)議之處在哪里呢?就是對(duì)職責(zé)的定義,什么是類的職責(zé),以及怎么劃分類的職責(zé)。下面舉個(gè)例子。

示例 一

正例:權(quán)限認(rèn)證(RBAC模式)(Role - Based Access Control,基于角色的訪問(wèn)控制,通過(guò)分

配和取消角色來(lái)完成用戶權(quán)限的授予和取消,使動(dòng)作主體(用戶)與資源的行為(權(quán)限)分離)。

1

2

1

2

再舉一個(gè)反例,用戶管理、修改用戶的信息、增加機(jī)構(gòu)(一個(gè)人屬于多個(gè)機(jī)構(gòu))、增加角色等,用戶有這么多的信息和行為要維護(hù),當(dāng)我們把這些寫(xiě)到一個(gè)接口中,都是用戶管理類嘛,如下示類圖:

用戶信息維護(hù)類圖

這個(gè)接口設(shè)計(jì)的問(wèn)題在于用戶的屬性和用戶的行為沒(méi)有分開(kāi),對(duì)于后期的維護(hù)特別不友好,應(yīng)該把用戶的信息

抽取成一個(gè)Bo(Bussiness Object,業(yè)務(wù)對(duì)象),把行為抽取成一個(gè)Biz(Business Logic,業(yè)務(wù)邏輯)

1

2

1

2

如下圖所示:

在這里插入圖片描述

代碼清單 1 - 1 分清職責(zé)后的代碼示例

.....

IUserBiz userInfo = new UserInfo();

//我要賦值了,我就認(rèn)為它是一個(gè)純粹的BO

IUserBO userBO = (IUserBO)userInfo;

userBO.setPassword("abc");

//我要執(zhí)行動(dòng)作了,我就認(rèn)為是一個(gè)業(yè)務(wù)邏輯類

IUserBiz userBiz = (IUserBiz)userInfo;

userBiz.deleteUser();

.....

1

2

3

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9

動(dòng)作分析:為什么要把一個(gè)接口拆分成兩個(gè)呢?其實(shí),在實(shí)際的使用中,我們更傾向于使用兩個(gè)不同的類或接口:一個(gè)是IUserBO,一個(gè)是IUserBiz,類圖如下圖所示。

在這里插入圖片描述

歸納:?jiǎn)我宦氊?zé)原則的定義是:應(yīng)該有且僅有一個(gè)原因引起類的變更

示例 二

電話這玩意,是現(xiàn)代人都離不開(kāi),電話通話的時(shí)候有4個(gè)過(guò)程發(fā)生:撥號(hào)、通話、回應(yīng)、掛機(jī),那我們寫(xiě)一個(gè)接口,其類圖下所示:

在這里插入圖片描述

代碼清單:電話過(guò)程

public interface Iphone {

//撥通電話

public void dial(String phoneNumber);

//通話

public void chat(Object o);

//通話完畢,掛電話

public void hangup();

}

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

這個(gè)接口乍看上去沒(méi)啥毛病,平常開(kāi)發(fā)也是這樣寫(xiě),單一職責(zé)原則要求一個(gè)接口或類只有一個(gè)原因引起變化,也就是一個(gè)接口或類只有一個(gè)職責(zé),它就負(fù)責(zé)一件事情,但是看上面的接口只負(fù)責(zé)一件事情嗎?是只有一個(gè)原因引起變化嗎?好像不是!

IPhone這個(gè)接口可不是只有一個(gè)職責(zé),它包含了兩個(gè)職責(zé):一個(gè)是協(xié)議管理,一個(gè)是數(shù)據(jù)傳送。dial()和hangup()兩個(gè)方法實(shí)現(xiàn)的是協(xié)議管理,分別負(fù)責(zé)撥號(hào)接通和掛機(jī);chat()實(shí)現(xiàn)的是數(shù)據(jù)的傳送,把我們說(shuō)的話轉(zhuǎn)換成模擬信息或數(shù)字信號(hào)傳遞到對(duì)方,然后再把對(duì)方傳遞過(guò)來(lái)的信號(hào)還原成我們聽(tīng)得懂的語(yǔ)言。我們可以這樣考慮這個(gè)問(wèn)題,協(xié)議接通的變化會(huì)引起這個(gè)接口或?qū)崿F(xiàn)類的變化嗎?會(huì)的!那數(shù)據(jù)傳送(想想看,電話不僅僅可以通話,還可以上網(wǎng))的變化會(huì)引起這個(gè)接口或?qū)崿F(xiàn)類的變化嗎?會(huì)的!那就很簡(jiǎn)單了,這里有兩個(gè)原因都引起了類的變化。這兩個(gè)職責(zé)會(huì)互相影響嗎?電話撥號(hào),我只要能接通就成,不管是電信的還是網(wǎng)通的協(xié)議;電話連接后還關(guān)心傳遞的是什么數(shù)據(jù)嗎?通過(guò)這樣的分析,我們發(fā)現(xiàn)類圖上的IPhone接口還包含了兩個(gè)職責(zé),而且這兩個(gè)職責(zé)的變化不互相影響,那就考慮拆分成兩個(gè)接口,如下圖所示:

在這里插入圖片描述

這個(gè)類圖看上去有點(diǎn)復(fù)雜了,完美滿足了單一職責(zé)原則的要求,每個(gè)接口職責(zé)分明,結(jié)構(gòu)清晰,但是一般在設(shè)計(jì)的時(shí)候不會(huì)采用這種方式,一個(gè)手機(jī)類要把ConnectionManager和DataTransfer組合在一塊才能使用。組合是一種強(qiáng)耦合關(guān)系,你和我都有共同的生命期,這樣的強(qiáng)耦合關(guān)系還不如使用接口實(shí)現(xiàn)的方式呢,而且還增加了類的復(fù)雜性,多了兩個(gè)類,經(jīng)過(guò)這樣的思考后,我們?cè)傩薷囊幌骂悎D,如下圖所示:

在這里插入圖片描述

這樣的設(shè)計(jì)才是完美的,一個(gè)類實(shí)現(xiàn)了兩個(gè)接口,把兩個(gè)職責(zé)融合在一個(gè)類中,你會(huì)覺(jué)得這個(gè)Phone有兩個(gè)原因引起變化了呀,是的,但是別忘記了我們是面向接口編程,我們對(duì)外公布的是接口而不是實(shí)現(xiàn)類。而且,如果真要實(shí)現(xiàn)類的單一職責(zé),這個(gè)就必須使用上面的組合模式了,這會(huì)引起類間耦合過(guò)重、類的數(shù)量增加等問(wèn)題,人為地增加了設(shè)計(jì)的復(fù)雜性。

總結(jié)

通過(guò)上面的例子,總結(jié)一下單一職責(zé)原則有什么好處:

1、類的復(fù)雜性降低,實(shí)現(xiàn)什么職責(zé)都有清晰明確的定義;

2、可讀性提高,復(fù)雜性降低,那當(dāng)然可讀性提高了;

3、可維護(hù)性提高,可讀性提高,那當(dāng)然更容易維護(hù)了;

4、變更引起的風(fēng)險(xiǎn)降低,變更是必不可少的,如果接口的單一職責(zé)做得好,一個(gè)接口修改只對(duì)相應(yīng)的實(shí)現(xiàn)類

有影響,對(duì)其他的接口無(wú)影響,這對(duì)系統(tǒng)的擴(kuò)展性、維護(hù)性都有非常大的幫助。

1

2

3

4

5

1

2

3

4

5

注意:?jiǎn)我宦氊?zé)原則提出了一個(gè)編寫(xiě)程序的標(biāo)準(zhǔn),用 “職責(zé)” 或 “變化原因” 來(lái)衡量接口或類設(shè)計(jì)得是否優(yōu)良,但是 “職責(zé)” 和 “變化原因” 都是不可度量的,因項(xiàng)目而異,因環(huán)境而異。

里氏替換原則

在面向?qū)ο蟮恼Z(yǔ)言中,繼承是必不可少的、非常優(yōu)秀的語(yǔ)言機(jī)制,它有如下優(yōu)點(diǎn):

1、代碼共享,減少創(chuàng)建類的工作量,每個(gè)子類都擁有父類的方法和屬性;

2、提高代碼的重用性;

3、子類可以形似父類,但又異于父類,“龍生龍,鳳生鳳,老鼠生來(lái)會(huì)打洞” 是說(shuō)子擁有父的 “種”,“世界上

沒(méi)有兩片完全相同的葉子” 是指明子與父的不同;

4、提高代碼的可擴(kuò)展性,實(shí)現(xiàn)父類的方法就可以 “為所欲為” 了,君不見(jiàn)很多開(kāi)源框架的擴(kuò)展接口都是通過(guò)

繼承父類來(lái)完成的;

5、提高產(chǎn)品或項(xiàng)目的開(kāi)放性

1

2

3

4

5

6

7

1

2

3

4

5

6

7

自然界的所有事物都是優(yōu)點(diǎn)和缺點(diǎn)并存的,即使是雞蛋,有時(shí)候也能挑出骨頭來(lái),繼承的缺點(diǎn)如下:

1、繼承是侵入性的,只要繼承,就必須擁有父類的所有屬性和方法;

2、降低代碼的靈活性。子類必須擁有父類的屬性和方法,讓子類自由的世界中多了些約束;

3、增加了耦合性。當(dāng)父類的常量、變量和方法被修改時(shí),必需要考慮子類的修改,而且在缺乏規(guī)范的環(huán)境下,

這種修改可能帶來(lái)非常糟糕的結(jié)果一大片的代碼需要重構(gòu)。

1

2

3

4

1

2

3

4

Java使用extends關(guān)鍵字來(lái)實(shí)現(xiàn)繼承,它采用了單一繼承的規(guī)則,C++則采用了多重繼承的規(guī)則,一個(gè)子類可以繼承多個(gè)父類。從整體上來(lái)看,利大于弊,怎么才能讓 “利” 的因素發(fā)揮最大的作用,同時(shí)減少 “弊” 帶來(lái)的麻煩呢? 解決方案是引入里氏替換原則 (Liskov Substitution Principle,LSP),什么是里氏替換原則呢?它有兩種定義:

第一種定義,也是最正宗的定義:如果對(duì)每一個(gè)類型為S的對(duì)象o1,都有類型為T(mén)的對(duì)象o2,使得以T定義的所有

程序P在所有的對(duì)象o1都代換成o2時(shí),程序P的行為沒(méi)有發(fā)生變化,那么類型S是類型T的子類型。

第二種定義:所有引用基類的地方必須能透明地使用其子類的對(duì)象。

1

2

3

4

1

2

3

4

第二個(gè)定義是最清晰明確的,通俗點(diǎn)講,只要父類能出現(xiàn)的地方子類就可以出現(xiàn),而且替換為子類也不會(huì)產(chǎn)生任何錯(cuò)誤或異常,使用者可能根本就不需要知道是父類還是子類。但是,反過(guò)來(lái)就不行了,有子類出現(xiàn)的地方,父類未必就能適應(yīng)。

示例 一

里氏替換原則為良好的繼承定義了一個(gè)規(guī)范,一句簡(jiǎn)單的定義包含了4層含義。

1.子類必須完全實(shí)現(xiàn)父類的方法,舉個(gè)例子,大家都打過(guò)CS吧,非常經(jīng)典的FPS類游戲,我們來(lái)描述一下里面用到的槍,如下圖:

在這里插入圖片描述

槍的主要職責(zé)是射擊,如何射擊在各個(gè)具體的子類中定義,手槍是單發(fā)射程比較近,步槍威力大射程遠(yuǎn),機(jī)槍用于掃射。在士兵類中定義了一個(gè)方法KillEnemy,使用槍來(lái)殺敵人,具體使用什么槍來(lái)殺敵人,調(diào)用的時(shí)候才知道,AbstractGun類的源程序

槍支的抽象類:

public abstract class AbstractGun {

//槍用來(lái)干什么?殺敵!

public abstract void shoot();

}

1

2

3

4

5

1

2

3

4

5

手槍、步槍、機(jī)槍的實(shí)現(xiàn)類如下面代碼

public class Handgun extends AbstractGun{

//手槍的特點(diǎn)是攜帶方便,射程短

@Override

public void shoot() {

System.out.println("手槍射擊...");

}

}

public class MachineGun extends AbstractGun{

@Override

public void shoot() {

System.out.println("機(jī)槍射擊...");

}

}

public class Rifle extends AbstractGun{

//步槍的特點(diǎn)是射程遠(yuǎn),威力大

@Override

public void shoot() {

System.out.println("步槍射擊...");

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

有了槍支,還要有能夠使用這些槍支的士兵,代碼清單如下:

士兵的實(shí)現(xiàn)類:

public class Soldier {

//定義士兵的槍支

private AbstractGun gun;

//給士兵一支槍

public void setGun(AbstractGun _gun) {

this.gun = _gun;

}

public void killEnemy() {

System.out.println("士兵開(kāi)始?xì)橙?..");

gun.shoot();

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

1

2

3

4

5

6

7

8

9

10

11

12

13

14

定義士兵使用槍來(lái)殺敵,但是這把槍是抽象的,具體是手槍還是步槍需要在戰(zhàn)場(chǎng)前(也就是場(chǎng)景中)前通過(guò)setGun方法確定。場(chǎng)景類Client的代碼如下所示:

public class Client {

public static void main(String[] args) {

//產(chǎn)生三毛這個(gè)士兵

Soldier sanMao = new Soldier();

//給三毛一支槍

sanMao.setG

標(biāo)題名稱:關(guān)于士兵殺敵java代碼的信息
鏈接URL:http://muchs.cn/article36/doccepg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、Google網(wǎng)站改版、用戶體驗(yàn)、定制開(kāi)發(fā)、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)