我对设计模式的理解:
多数开发人员应该知道设计模式这个东西;部分人知道23种设计模式;少数人能够熟练使用设计模式,极少数人精通设计模式。
其实23种设模式,其实只是入门,这就相当于你学英语,学会了26个英文字母,才能开始学习单词。同样23种设计模式,只是字母表,想要到精通的层次,要能够灵活的使用设计模式,灵活的组合设计模式。
设计模式是我短期计划中的一部分,我的文章致力于最快最简单的掌握每一个设计模式。
我的设计模式相关的文章,都会在开篇使用一句话,来描述一个设计模式!
该模式设计关键点使用抽象类,定义算法骨架,然后子类根据不同的场景来实现算法细节,达到解决不同问题的目的。
最大的好处
代码复用,代码结构清晰,符合开闭原则。
最大的缺点
类的个数膨胀。
UML图
该设计模式非常的简单,很容易掌握,也比较容易用到。
定义一个抽象类(红色框),算法骨架方法,跟业务挂钩的抽象方法;
然后由实现类,去实现跟自己业务相关的方法。
简单的使用
(一般大家对游戏比较有共鸣,那就举一个游戏的栗子吧):
首先我定义了一个抽象类:AbstractGame
该抽象类有五个方法,其中两个两个用final修饰的方法,其中一个是算法骨架,openGame(),该方法里边定义好了算法的执行流程,必须按照我预期的进行加载。我不想让子类擅自修改我们的算法骨架,所以我用final来修饰。
另外三个方法是抽象方法,分别是加载场景,和加载背景音乐的,和连接用户的方法。
abstract class AbstractGame {
/**
* 游戏算法骨架
*/
final void openGameTempl(){
//加载游戏场景
loadScene();
//加载背景音乐
loadBackgroundMusice();
//连线游戏用户
connectedUsers();
//开始游戏
begin();
}
/**
* 加载游戏场景
*/
abstract void loadScene();
/**
* 加载背景音乐
*/
abstract void loadBackgroundMusice();
/**
* 连线游戏用户
*/
abstract connectedUsers();
/**
* 开始游戏
*/
final void begin(){
System.out.println("欢迎来到召唤师峡谷");
}
}
接着是实现类,三个方法是抽象方法,分别是加载场景,和加载背景音乐的,和连接用户的方法。如果想加载不同的游戏地图进来,则可以用子类去继承我们的抽象方法。如果想要是使用不同的连接用户的方法,使用语音,使用第三方聊天工具。
同样道理,如果是3v3 的游戏,则再定义一个子类来实现AbstractGame。 游戏的加载顺序是不变的,唯一边的就是我们的抽象方法。
class GameV5 extends AbstractGame{
/**
* 加载游戏场景
*/
@Override
void loadScene(){
System.out.println("加载5v5的游戏地图");
}
/**
* 加载背景音乐
*/
@Override
void loadBackgroundMusice(){
System.out.println("加载大乱斗的背景音乐");
}
/**
* 连线游戏用户
*/
@Override
void connectedUsers(){
System.out.println("使用QT语音进行用户的连接");
}
}
想要开始一场5V5的游戏,则直接new一个对象即可。
public class DoGame {
public static void main(String[] args) {
GameV5 gameV5 = new GameV5();
gameV5.openGameTempl();
}
}
灵活运用-模板方法下的钩子程序
其实这个是非常灵活的,还可以定义下边的四个方法为抽象方法。唯独定义全部的方法为抽象方法,不太合适。留出一个方法来定义算法骨架,这是模板方法的一个精髓点。
同事,我们还可以不把抽象类写太死,预留出来一些权利给子类。也就是通常说的钩子程序。
下边我对上边的案例做一点改变
abstract class AbstractGame {
/**
* 游戏算法骨架
*/
final void openGameTempl(){
//加载游戏场景
loadScene();
//加载背景音乐
loadBackgroundMusice();
//连线游戏用户
connectedUsers();
//开始游戏
begin();
}
/**
* 加载游戏场景
*/
abstract void loadScene();
/**
* 加载背景音乐
*/
abstract void loadBackgroundMusice();
/**
* 预留一个钩子,由子类决定是否加载
*/
if(isLoadSkin()){
//加载皮肤
loadSkin();
}
/*
* 是非加载皮肤
*/
protected boolean isLoadSkin(){
return false;
}
/**
* 连线游戏用户
*/
abstract connectedUsers();
/**
* 开始游戏
*/
final void begin(){
System.out.println("欢迎来到召唤师峡谷");
}
}
在实现类中决定,是否加载皮肤。
class GameV5 extends AbstractGame{
/**
* 加载游戏场景
*/
@Override
void loadScene(){
System.out.println("加载5v5的游戏地图");
}
/**
* 加载背景音乐
*/
@Override
void loadBackgroundMusice(){
System.out.println("加载大乱斗的背景音乐");
}
/**
* 连线游戏用户
*/
@Override
void connectedUsers(){
System.out.println("使用QT语音进行用户的连接");
}
/*
* 是非加载皮肤
*/
@Override
protected boolean isLoadSkin(){
return true;
}
}
想要开始一场5V5的游戏,则直接new一个对象即可。
public class DoGame {
public static void main(String[] args) {
GameV5 gameV5 = new GameV5();
gameV5.openGameTempl();
}
}