资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

关于士兵杀敌java代码的信息

求一款手机单机游戏的名字,以前在按键机上玩过的Java游戏,走格子的战旗回合类,主角是亚瑟王可以造兵

我也正在找这款游戏,同问,以前在诺基亚上玩过。不过最早玩的一个版本是以隋唐为背景的,主角是唐太宗李世民,步兵弓手术士(水兵)骑兵枪兵(重步兵)最强是投石机,不同地形对不同兵种有加成,祭司召唤尸体完全相同,有剧情,最终BOSS也是远程打击。还有自由对战模式超好玩的,简直就是策略战棋启蒙,可是这么多年过去已经找不到了。

创新互联 - 成都服务器托管,四川服务器租用,成都服务器租用,四川网通托管,绵阳服务器托管,德阳服务器托管,遂宁服务器托管,绵阳服务器托管,四川云主机,成都云主机,西南云主机,成都服务器托管,西南服务器托管,四川/成都大带宽,机柜大带宽,四川老牌IDC服务商

下图属于哪一类设计原则

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

java

打开APP

成胜文

关注

设计模式 — 6大设计原则(单一职责和里氏替换原则) 原创

2022-11-04 01:26:20

成胜文

码龄4年

关注

6大设计原则

说明

单一职责原则

示例 一

示例 二

总结

里氏替换原则

示例 一

示例 二

示例 三

总结

说明

6大设计原则来自于观看 “设计模式之禅” 一书后的总结

单一职责原则

单一职责原则的英文名称是Single Responsibility Principle,简称是SRP。这个原则存在争议之处在哪里呢?就是对职责的定义,什么是类的职责,以及怎么划分类的职责。下面举个例子。

示例 一

正例:权限认证(RBAC模式)(Role - Based Access Control,基于角色的访问控制,通过分

配和取消角色来完成用户权限的授予和取消,使动作主体(用户)与资源的行为(权限)分离)。

1

2

1

2

再举一个反例,用户管理、修改用户的信息、增加机构(一个人属于多个机构)、增加角色等,用户有这么多的信息和行为要维护,当我们把这些写到一个接口中,都是用户管理类嘛,如下示类图:

用户信息维护类图

这个接口设计的问题在于用户的属性和用户的行为没有分开,对于后期的维护特别不友好,应该把用户的信息

抽取成一个Bo(Bussiness Object,业务对象),把行为抽取成一个Biz(Business Logic,业务逻辑)

1

2

1

2

如下图所示:

在这里插入图片描述

代码清单 1 - 1 分清职责后的代码示例

.....

IUserBiz userInfo = new UserInfo();

//我要赋值了,我就认为它是一个纯粹的BO

IUserBO userBO = (IUserBO)userInfo;

userBO.setPassword("abc");

//我要执行动作了,我就认为是一个业务逻辑类

IUserBiz userBiz = (IUserBiz)userInfo;

userBiz.deleteUser();

.....

1

2

3

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9

动作分析:为什么要把一个接口拆分成两个呢?其实,在实际的使用中,我们更倾向于使用两个不同的类或接口:一个是IUserBO,一个是IUserBiz,类图如下图所示。

在这里插入图片描述

归纳:单一职责原则的定义是:应该有且仅有一个原因引起类的变更

示例 二

电话这玩意,是现代人都离不开,电话通话的时候有4个过程发生:拨号、通话、回应、挂机,那我们写一个接口,其类图下所示:

在这里插入图片描述

代码清单:电话过程

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

这个接口乍看上去没啥毛病,平常开发也是这样写,单一职责原则要求一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责,它就负责一件事情,但是看上面的接口只负责一件事情吗?是只有一个原因引起变化吗?好像不是!

IPhone这个接口可不是只有一个职责,它包含了两个职责:一个是协议管理,一个是数据传送。dial()和hangup()两个方法实现的是协议管理,分别负责拨号接通和挂机;chat()实现的是数据的传送,把我们说的话转换成模拟信息或数字信号传递到对方,然后再把对方传递过来的信号还原成我们听得懂的语言。我们可以这样考虑这个问题,协议接通的变化会引起这个接口或实现类的变化吗?会的!那数据传送(想想看,电话不仅仅可以通话,还可以上网)的变化会引起这个接口或实现类的变化吗?会的!那就很简单了,这里有两个原因都引起了类的变化。这两个职责会互相影响吗?电话拨号,我只要能接通就成,不管是电信的还是网通的协议;电话连接后还关心传递的是什么数据吗?通过这样的分析,我们发现类图上的IPhone接口还包含了两个职责,而且这两个职责的变化不互相影响,那就考虑拆分成两个接口,如下图所示:

在这里插入图片描述

这个类图看上去有点复杂了,完美满足了单一职责原则的要求,每个接口职责分明,结构清晰,但是一般在设计的时候不会采用这种方式,一个手机类要把ConnectionManager和DataTransfer组合在一块才能使用。组合是一种强耦合关系,你和我都有共同的生命期,这样的强耦合关系还不如使用接口实现的方式呢,而且还增加了类的复杂性,多了两个类,经过这样的思考后,我们再修改一下类图,如下图所示:

在这里插入图片描述

这样的设计才是完美的,一个类实现了两个接口,把两个职责融合在一个类中,你会觉得这个Phone有两个原因引起变化了呀,是的,但是别忘记了我们是面向接口编程,我们对外公布的是接口而不是实现类。而且,如果真要实现类的单一职责,这个就必须使用上面的组合模式了,这会引起类间耦合过重、类的数量增加等问题,人为地增加了设计的复杂性。

总结

通过上面的例子,总结一下单一职责原则有什么好处:

1、类的复杂性降低,实现什么职责都有清晰明确的定义;

2、可读性提高,复杂性降低,那当然可读性提高了;

3、可维护性提高,可读性提高,那当然更容易维护了;

4、变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类

有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。

1

2

3

4

5

1

2

3

4

5

注意:单一职责原则提出了一个编写程序的标准,用 “职责” 或 “变化原因” 来衡量接口或类设计得是否优良,但是 “职责” 和 “变化原因” 都是不可度量的,因项目而异,因环境而异。

里氏替换原则

在面向对象的语言中,继承是必不可少的、非常优秀的语言机制,它有如下优点:

1、代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;

2、提高代码的重用性;

3、子类可以形似父类,但又异于父类,“龙生龙,凤生凤,老鼠生来会打洞” 是说子拥有父的 “种”,“世界上

没有两片完全相同的叶子” 是指明子与父的不同;

4、提高代码的可扩展性,实现父类的方法就可以 “为所欲为” 了,君不见很多开源框架的扩展接口都是通过

继承父类来完成的;

5、提高产品或项目的开放性

1

2

3

4

5

6

7

1

2

3

4

5

6

7

自然界的所有事物都是优点和缺点并存的,即使是鸡蛋,有时候也能挑出骨头来,继承的缺点如下:

1、继承是侵入性的,只要继承,就必须拥有父类的所有属性和方法;

2、降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;

3、增加了耦合性。当父类的常量、变量和方法被修改时,必需要考虑子类的修改,而且在缺乏规范的环境下,

这种修改可能带来非常糟糕的结果一大片的代码需要重构。

1

2

3

4

1

2

3

4

Java使用extends关键字来实现继承,它采用了单一继承的规则,C++则采用了多重继承的规则,一个子类可以继承多个父类。从整体上来看,利大于弊,怎么才能让 “利” 的因素发挥最大的作用,同时减少 “弊” 带来的麻烦呢? 解决方案是引入里氏替换原则 (Liskov Substitution Principle,LSP),什么是里氏替换原则呢?它有两种定义:

第一种定义,也是最正宗的定义:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有

程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。

第二种定义:所有引用基类的地方必须能透明地使用其子类的对象。

1

2

3

4

1

2

3

4

第二个定义是最清晰明确的,通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

示例 一

里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含了4层含义。

1.子类必须完全实现父类的方法,举个例子,大家都打过CS吧,非常经典的FPS类游戏,我们来描述一下里面用到的枪,如下图:

在这里插入图片描述

枪的主要职责是射击,如何射击在各个具体的子类中定义,手枪是单发射程比较近,步枪威力大射程远,机枪用于扫射。在士兵类中定义了一个方法KillEnemy,使用枪来杀敌人,具体使用什么枪来杀敌人,调用的时候才知道,AbstractGun类的源程序

枪支的抽象类:

public abstract class AbstractGun {

//枪用来干什么?杀敌!

public abstract void shoot();

}

1

2

3

4

5

1

2

3

4

5

手枪、步枪、机枪的实现类如下面代码

public class Handgun extends AbstractGun{

//手枪的特点是携带方便,射程短

@Override

public void shoot() {

System.out.println("手枪射击...");

}

}

public class MachineGun extends AbstractGun{

@Override

public void shoot() {

System.out.println("机枪射击...");

}

}

public class Rifle extends AbstractGun{

//步枪的特点是射程远,威力大

@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

有了枪支,还要有能够使用这些枪支的士兵,代码清单如下:

士兵的实现类:

public class Soldier {

//定义士兵的枪支

private AbstractGun gun;

//给士兵一支枪

public void setGun(AbstractGun _gun) {

this.gun = _gun;

}

public void killEnemy() {

System.out.println("士兵开始杀敌人...");

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

定义士兵使用枪来杀敌,但是这把枪是抽象的,具体是手枪还是步枪需要在战场前(也就是场景中)前通过setGun方法确定。场景类Client的代码如下所示:

public class Client {

public static void main(String[] args) {

//产生三毛这个士兵

Soldier sanMao = new Soldier();

//给三毛一支枪

sanMao.setG


网页名称:关于士兵杀敌java代码的信息
URL标题:http://cdkjz.cn/article/doccepg.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220