足球战术之设计模式篇 (0分)

V

VRGL

Unregistered / Unconfirmed
GUEST, unregistred user!
足球战术中最重要的应该是队员的跑动,而对于全体队员的跑动应该符合observer模式
才对。因为作为subject的传球队员不仅仅是要对被传球的队员发送消息,而且要改变所有
队员(observers)的跑动方式。广播的方式应该分为两种情况:推和拉。被传球的队员是接收
推的方式,由传球队员的传球路线直接引导他的跑动路线。其他队员是接收拉的方式,由
视觉接受传球队员的跑动及传球路线继而决定自己的跑动。代码如下:
class 无球队员{
public:
virtual ~观察();
virtual void 跑动(传球队员* 传球路线)=0;
protected:
观察();
};
class 传球队员{
public:
virtual ~传球消息();
virtual void 准备传球(无球队员*);
virtual void 继续带球(无球队员*);
virtual void 传球();
protected:
传球消息();
private:
List<无球队员*> *_无球队员;
};
void 传球消息::准备传球(无球队员* 对象){
_无球队员->开始观察(对象);
}
void 传球消息::继续带球(无球队员* 对象){
_无球队员->停止跑动;
}
void 传球消息::传球(){
ListIterator<无球队员*> i(_无球队员);
for (i.First();i.IsDone();i.Next()){
i.CurrentItem()->传球后更新跑动(this);
}
}
队形的保持需要memento模式,特别是两个边后卫,上一场意甲AC米兰输给佩努贾,
主要是因为边后卫助攻后未回原位所致。这里使用memento主要是象使用contra那样
让边后卫兼任边前卫,但如果队员能力不足,或防守任务过于艰巨,以至于需要边后卫
反复无效的来回奔跑则不应该使用此模式。这里由教练事先演练的算法,由一个虚拟的
caretaker由进攻的需要向边后卫(originator)发出请求,生成一个虚拟的memento,
后卫前插助攻,防守时边后卫因为caretaker的防守需要的请求,返回到memento的位置。
代码如下:
class 边后卫{
public:
防守位置* 创建防守位置();
void 设置防守位置(const 防守位置*);
private:
位置* _位置;
};
class 防守位置{
public:
virtual ~防守位置();
pivate:
friend class 边后卫;
防守位置();
void 设置位置(位置*);
位置* 得到位置();
private:
位置* _位置;
};
 
向你致敬[:D]
 
转帖请注明出处和原作者
 
上次忘了最古老的足球战术->中场发动机战术,也就是mediator模式,
在这个模式中,所有的中场组织都由中场发动机(mediator)来完成。
对其他队员(colleague)的要求降低,而对中场发动机的要求大大提高。
传球方式分两种,第一种由普通的observer模式得来:将中场发动机
作为observer,其他队员作为subject,由中场发动机将其他队员的传球
再传给其他人;第二种由其他队员把自己作为参数传给中场发动机,
跑动后中场发动机再把球传给他,做踢墙式二过一。代码如下:
class 中场发动机{
public:
virtual ~中场发动机();
virtual void 中转();
virtual void 其他队员的传递(其他队员*)=0;
protected
中场发动机();
virtual void 带球,寻找可传球人()=0;
};
class 其他队员{
public:
其他队员(中场发动机*);
virtual void 进攻变化();
virtual void 传球(传球事件&amp;
事件);
private:
中场发动机* _发动机;
};
void 其他队员::进攻变化(){
_发动机->其他队员的传递(this);
}
 
长传冲调高中锋战术,也就是singleton,是最烂,
也是最快最直接的战术,它的特点是,所有球都
采用长传的方式直接冲调高中锋,所有的攻势都
只有一个实例,也就是高中锋。这个方法的好处
是简单实用,而且易于扩展复用:)复用后的
战术仍然只有一个实例,再急于扳平时可以使用。
还有就是高中锋的访问方法是严格控制的,同时
不采用让高中锋静态全局等待的方法,因为那样
会污染名字空间(也就是整体战术)。还有单个
高中锋是实实在在的(不是virtual),那样复用的
子战术不会变成多态的二高中锋或三高中锋,目标明确:p
代码如下:
class 高中锋{
public:
static 高中锋* 实例();
protected:
高中锋();
private:
static 高中锋* _实例;
};
高中锋* 高中锋::_实例=0;
高中锋* 高中锋::实例(){
if(_实例==0){
_实例=new 高中锋;
}
return _实例;
}
 
在由攻转守的过程中可以采用Template method模式,
即基本算法进攻->转换->防守不变,在子类中具体
实现转换的内容,可以全速退防,或者就地抢劫等等,
代码如下:
void 球队::由攻转守(){
进攻();
中间转化过程();
防守();
}
void 球队::中间转化过程(){}
void 子类球队::中间转化过程(){
//就地抢劫或全速退防等等
}
 
在足球战术中常常使用边锋战术,也就是Decorator模式。
主要优点是可以在不改变球队整体战术的前提下,增加
一个左边锋或者右边锋,增加进攻的威胁。缺点是有时候
并不好控制,必须要保持边前锋和全队的接口的一致性。
如果全队的打法过于繁杂,则使用边前锋的代价太高。
一定要打法简练实用的球队(如荷兰队对overmars)才可以
用此模式。对于打法繁杂的球队可以使用strategy模式。
代码如下:
class 球队{
public:
球队();
virtual void 进攻();
virtual void 组织();
};
class 边锋:public 球队{
public:
边锋(球队*);
virtual void 进攻();
virtual void 组织();
private:
球队* _实例;
};
void 边锋::进攻(){
_实例->进攻();
}
void 边锋::组织(){
_实例->组织();
}
class 左边锋:public 边锋{
public:
左边锋(球队*,int 左边宽度);
virtual void 进攻();
private:
void 左边进攻(int);
private:
int _宽度;
};
void 左边锋::进攻(){
边锋::进攻();
左边进攻(_宽度);
}
 
球队的每个球员都代表一种战术,也就是strategy模式。
由于每个球员代表一个strategy,避免了整体球队战术的
复杂性。比如米兰的德比大战,AC米兰先失一球,而表示
防守战术的Albertini又状态不佳,于是换上表示进攻战术
的很具活力的contra,5分钟之类连下3城,反败为胜。但
由于分工明确,教练必须对每个队员的特性非常熟悉。而且
各队员之间的磨合也较为困难,且战术分散,不利于整体配合。
代码如下:
class 球队{
public:
球队(球员*);
void 组织();
private:
球员* _球员;
整体战术* _整体;
int _球员数目;
}
class 球员{
public:
virtual int 组织(所有参数)=0;
protected:
球员();
};
 
写的很好!谢谢你辛苦的劳动。用pasecal代码表示会有更多人相应。
 
通俗,精辟!
 
这个是球队的基本建设,为了组建好一支国家队,
而国内有成千上万的优秀队员,而每个人的特性
都不同,要使他们组建成一支11个人的优秀球队,
必须按照442的阵形严格区分每个队员的分工,如
前腰,后腰,左前卫,右后卫等等。这样可以把
每个位置作一个享元,也就是flyweight,防止产生
大量过多的对象,妨碍球队阵形的稳固,也开销大,
难于维护。
代码如下:
class 位置{
public:
virtual ~位置();
virtual void 踢球(球队*);
protected:
位置();
}
class 具体位置:public 位置{
public:
具体位置();
virtual void 踢球(球队*);
private:
char _球衣号;
};
class 位置工厂{
public:
位置工厂();
virtual ~位置工厂();
virtual 具体位置* 创建具体位置(char);
private:
具体位置* _具体位置(最大球衣号);
};
位置工厂::位置工厂(){
for(int i=0;i<最大球衣号;++i){
_具体位置=0;
}
}
具体位置* 位置工厂::创建具体位置(char 球衣号){
if (!_具体位置){
_具体位置(球衣号)=new 具体位置(球衣号);
}
 
用前锋,前卫甚至后卫来多点进攻,是最好的进攻方法,
在这里可以使用abstract factory模式,用一个abstract
factory来创建一个统一的进攻位置,然后派生出具体的
concrete factory(具体位置)来生产concrete product
(进球),所有的进攻由client class(教练)来指挥。
缺点是基本打发已经定死,没有什么创造性
的进球方法,如肩部进球,胸部进球和“上
帝之手”等等:p
代码如下:
T位置 = class(TObject)
public
constructor Create;
destructor Destroy;
override;

function 头球(AOwner: TComponent): T头球得分;
virtual;
abstract;
function 近射(AOwner: TComponent): T近射得分;
virtual;
abstract;
function 远射(AOwner: TComponent): T远射得分;
virtual;
abstract;
end;

T前锋 = class(T位置)
public
{ concrete constructors }
function 前锋头球(AOwner: TComponent): T前锋头球得分;
override;
function 前锋近射(AOwner: TComponent): T前锋近射得分;
override;
function 前锋远射(AOwner: TComponent): T前锋远射得分;
override;
end;

T后卫 = class(T位置)
public
{ concrete constructors }
function 后卫头球(AOwner: TComponent): T后卫头球得分;
override;
function 后卫近射(AOwner: TComponent): T后卫近射得分;
override;
function 后卫远射(AOwner: TComponent): T后卫远射得分;
override;
end;
 
最有效的进攻方法是几个球员组合成composite来进攻,
这个composite又可以和其他球员和composite组合成
新的composite,如此递归...Composite模式简化了
教练(client)的指挥,因为他不用考虑某个进攻模块
是单个队员还是composite,而且也容易在原战术上
加入新增加的队员或composite,但是使用起来会出现
你不希望某个进攻组合中有某个队员或组合时,你无法
限制他们,只有在比赛进行中灵活运用。
代码如下:
class 组合;
class 组件{
public:
virtual 组合* 得到组合(){return 0;}
};
class 组合:public 组件{
public:
void 添加(组件*);
virtual 组合* 得到组合(){return this;}
};
class 队员:public 组件{
};
组合* a组合=new 组合;
队员* a队员=new 队员;
组件* a组件;
组合* test;
a组件=a组合;
if(test=a组件->得到组合()){
test->添加(new 队员);
}
a组件=a队员;
if(test=a组件->得到组合()){
test->添加(new 队员);
}
注:组件为一个组合或队员。
 
横传捣脚转移是找出进攻突破口的最好的方法,中国队
这次十强赛最大的进步就是这方面。这比较符合
chain of resposibility模式。整个前锋,前卫,和
后卫线形成一条链,对每个队员解耦,把进攻请求
按一个一个队员(对象)传过去,直到机会出现,
合适的队员完成进攻。好处是队员不用知道机会
什么时候出现,只要从对方队员密集处(无法完成
进攻)向对方队员稀疏处(易于完成进攻)转移。
可随机改变打发,利于灵活处理进攻任务。缺点是
可能捣了半天也没得到进攻机会,反被对方断球,
被打反击。代码如下:
class 队员{
public:
队员(队员* s):_后继(s){}
virtual void 处理球();
private:
队员* _后继;
};
void 队员::处理球(){
if(_后继){
_后继->处理球();
}
}
void 队员::处理进攻请求(请求* the请求){
switch(the请求->得到类型()){
case 射门:
处理射门((射门请求*)the请求);
break;
case 突破:
处理突破((突破请求*)the请求);
break;
default:
break;
}
}
class 具体队员:public 队员{
public:
virtual void 处理请求(请求* the请求);
};
void 具体队员::处理请求(请求* the请求){
switch(the请求->得到类型()){
case 突破分球:
//处理突破分球
break;
default:
//处理其它请求
队员::处理请求(the请求);
}
}
 
训练时公布给外界的是一套,而
正式比赛时是另外一套,所谓是
声东击西,可以运用bridge模式。
好处是训练和比赛分离,提高各自
的可扩充性,而且实现细节对客户
(外界)透明:)
代码如下:
class 训练球队{
public:
训练球队();
virtual void 加强左路进攻();
virtual void 加强右路进攻();
protected:
比赛球队* 得到比赛球队();
private:
比赛球队* _实现;
};
class 比赛球队{
public:
virtual void 加强左路进攻();
virtual void 加强右路进攻();
protected:
比赛球队();
};
class 扩展训练球队:public 训练球队{
public:
//...
virtual void 佯攻左路,实攻右路();
private:
const char* _右路队员号码;
};
class 扩展比赛球队:public 比赛球队{
public:
扩展比赛球队();
virtual void 佯攻右路,实攻左路();
//...
private:
const char* _左路队员号码;

};
 
足球中的进攻可以采用command模式,
前锋的位置是command,主力前锋和
替补前锋是ConcreteCommand,client
是教练,invoker是中场及后卫球员。
好处是将前锋和其他策动进攻的球员
解耦。并且前锋也可以向其他队员一样
被操纵和扩展。新增一个前锋很容易,
因为无需改变其他队员:)
代码如下:
class 前锋{
public:
virtual ~前锋();
virtual void 进攻()=0;
protected:
前锋();
};
class 主力前锋:public 前锋{
public:
主力前锋(教练*);
virtual void 进攻();
private:
教练* _教练;
};
class 替补前锋:public 前锋{
public:
替补前锋(教练*);
virtual void 进攻();
private:
教练* _教练;
};
 
佩服,佩服!
 
象AC Milan的三叉戟是球队的核心,而其他队员
都只是工兵型的球员。所以可以把三叉戟作为
一个facade来用。好处是对客户(教练)屏蔽了
其他队员,减少了客户(教练)处理的对象数目
并使子系统使用起来更方便;实现了子系统与
客户(教练)之间的松耦合关系,而队员之间是
紧耦合的;如果需要,并不妨碍客户(教练)使用
其他球员,因此你可以在系统(球队)易用性和通
用型之间加以选择。
代码如下:
class 其他球员{
public:
其他球员();
virtual ~其他球员();
}
class 三叉戟{
public:
三叉戟();
virtual void 联系();
};
void 三叉戟::联系()
{其他球员 其他球员();
}
 
采用全攻全守的打法,使用visitor模式,
每个队员是一个visitor,每个位置是一个
node,好处是每加一个新的队员,就增加
一种新的进攻或防守方法,每个队员集中
了他的优点和相关的打法,分离了其他打法
到其他队员身上。但是位置已经定死,增加
新位置比较困难。通过全场的位置结构和队
员特性(类层次)进行访问。当某个队员跑到
某个位置时,他的操作会作为累积状态影响
其他队员的操作。由于全攻全守要求每个位置
的队员的能力都很强,所以往往会造成主力前锋
必须要有当中后卫能力之类的混乱局面,也就是
node要给visitor提供访问其内部状态的公共操作,
破坏了封装性:)
代码如下:
class 队员{
public:
virtual void 访问前锋位置(前锋位置*);
virtual void 访问后卫位置(后卫位置*);
//...访问其它位置的方法
protected:
队员();
};
class 位置{
public:
virtual ~位置();
virtual void 接受(队员&amp;)=0;
protected:
位置();
};

 
在比赛时根据球员的状态来决定他的表现,
可以使用state模式。其中球队是context,
球员是state,教练是client。好处是将特定
状态相关的行为局部化,并且将不同状态的
行为分割开来;使得状态转换显示化;而且
球员可以被多个教练(client)共享。
代码如下:
class 球队{
public:
球队();
private:
friend class 球员;
void 改变状态(球员*);
private:
球员* _状态;
};
class 球员{
public:
//所有操作
protected:
void 改变状态(球队*,球员*);
};
class 球员状态不佳:public 球员{
public:
static 球员* 实例();
virtual void 坐冷板凳(球队*);
};
class 球员状态很好:public 球员{
public:
static 球员* 实例();
virtual void 上场首发(球队*);
};
 

Similar threads

D
回复
0
查看
902
DelphiTeacher的专栏
D
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
613
import
I
顶部