设计模式
使用场景
软件架构和程序设计
目的
1.提高代码的可重用性
2.提高代码的可读性
3.保障代码的可靠性
设计原则特点
1.可扩展性(Extensibility)
2.灵活性(Flexibility)
3.组件化可插拔式(Pluggability)
准则
- 单一职责原则:一个Java类存放的功能不能实现不同属性的功能,吃饭和睡觉这是两件事,需要分开创建对象。
class HandleUser{
// 增删改查 操作用户 登录注册功能
public User getUser(){};
public void updateUser(int id){};
public void saveUser(int id){};
public void removeUser(int id){};
// 用户玩游戏
public void userPlayGame();
}
/**
*
* 这两个功能是不是不应该杂糅在一起,所以需要创建两个Java类,来存放不同功能
*
*/
class UserHandleDao{
// 增删改查 操作用户 登录注册功能
public User getUser(){};
public void updateUser(int id){};
public void saveUser(int id){};
public void removeUser(int id){};
}
class UserBusinessDao{
// 用户玩游戏
public void userPlayGame(){};
}
- 开闭原则:软件对外的扩展开放,对外修改关闭,吃饭你得选择吧,有选择就有需求,有需求就有喜好,比如你喜欢吃西红柿,那么你还是需要品尝人间美食,没有吃过的食物自然需要你的尝试,才能确定好吃与否,但再好的美食也不会影响你原本喜好的美食,这是一样的道理。
class UserBusinessImpl{
@注入
private ConncetMouxinUtil;
// 普通用户玩游戏 国王游戏
public void ordinaryUserPlayGame(){};
// VIP用户玩游戏
public void VipUserPlayGame(){};
}
/**
*
* 用户玩本公司的游戏,以及登录注册游戏账号,但是呢大家都是有身份的人,怎么会没有某信账号
* 什么?没有某信注册账号,对不起我不玩辣鸡游戏
* 这时我们需要外接接口,挽救玩家
*
*/
class ConncetMouxinUtil{
// 软件的扩展,但是也拒绝其某信修改或者获取软件数据
public void connectMouxin(){};
}
- 里氏代换原则:具备相同属性功能总结到一个父类,而子类继承父类属性和功能,打个比方,妈妈和女儿,爸爸和儿子,四人家庭,女儿和儿子都继承自爸爸和妈妈的优秀基因,自出生一刻,身材长相全都由父母提供,你也具备了和父母一样的寿命,思想,意识,智慧,全都继承自你的父母,当然人类还有很多不同属性,所以不能归纳到一个父类中,你的性格和未来发展等等。
class TravelerKong{
// 技能:裂空之剑
public void skillLiekongZhijian(String AKey){
System.out.println("造成9999伤害!");
}
}
class TravelerYing{
// 技能:异邦铁风
public void skillYibangTiefeng(String BKey){
System.out.println("造成100000伤害!");
}
}
/**
*
* 你看空和荧的技能参数一样,功能也一样,只是输出不一样
* 可要是每个人物都写这样无数的技能,维护和板砖都是极不友好
* 平A你都要给写一个对象吗
*
*/
class TravelerTian{
// 技能:万物归一
public void skillWanwuGuiyi(String AKey,String hurt){
System.out.println(hurt);
}
}
class TravelerKong extends TravelerTian{
@Override
public void skillWanwuGuiyi(String AKey,String hurt){
// 非空判断省略了
if( AKey == KEY_FLG )
System.out.println(hurt);
}
}
class TravelerYing extends TravelerTian{
private static final String KEY_FLG = "1";
@Override
public void skillWanwuGuiyi(String AKey,String hurt){
if( AKey == KEY_FLG )
System.out.println(hurt);
}
}
class PersonageTest{
private static final String KONG_HURT = "造成9999伤害!";
private static final String YING_HURT = "造成100000伤害!";
private static final String KEY_FLG = "1";
@Test
public void GameTest(){
TravelerTian tk = new TravelerKong();
// 某某调用了这个方法 判断省略了
tk.skillWanwuGuiyi(parma , KONG_HURT);
TravelerTian ty = new TravelerYing();
// 某某调用了这个方法 判断省略了
ty.skillWanwuGuiyi(parma , YING_HURT );
}
}
- 依赖倒转原则:面向接口编程,接口只是申明具体动作的别称,形容这是一个怎样的动作,所以不具备具体的发生动作的过程,想要真正描绘出动作的过程,此时,需要一个Java类实现implements某个动作别名的接口,举例来说,睡觉,坐着睡和躺着睡,坐着睡只是一个叫法,具体需要我们细致观察后,我葛优躺在一张长凳上睡着了,微张的小嘴发出轰隆隆的鼾声,哈喇子不争气的流了一条小河,这就是具体的坐着睡的行为描述,完整的将整个睡觉的动作具象化,躺着睡也是一样的情形。
class interface MyGame {
void LOL();
void YuanShen();
void CF();
void WangZheRongYang();
.......
}
/**
*
* 接口只是一个万物的名字代称,不具备业务实现
* 而我们将这类相同属性的事务,归纳到一个接口中,这就是我所理解的面向接口编程
*
*/
class UserGame implements MyGame {
// 接口需要全部实现方法
public void LOL(){};
public void YuanShen(){};
public void CF(){};
public void WangZheRongYang(){};
}
- 接口隔离原则:相似的动作,处理数据行为,统一使用不同接口分别存放,类似于坐着睡、躺着睡这两个行为是一个动作,存放一个接口;而狼吞虎咽的吃饭,细嚼慢咽的品尝食物,又是一个动作,需要另一个接口存放。
class interface MyGame {
void LOL();
void YuanShen();
void CF();
void WangZheRongYang();
void aOiSoLa();
}
/**
*
* aOiSoLa()这是什么鬼?你们细细品会,这两个东西当然不能放在一起,会出大事的!
*
*/
- 合成复用原则:在系统中尽量使用组合和聚合关联,少使用继承关系,会造成代码的耦合,很简单的讲,你和你哥们,会在一件认爹这事上达成事实吗?这时,我们就需要口头上事实,一口一口儿子的叫,但是儿子而不会真的认你当爹,真把你当爹了,随之就是多了个儿子,还要给儿子好处,那是万万不行的,儿子就是儿子,不应该要爹的好处,所以我们叫儿子的时候,一惯作风拿来用,跑腿去食堂带饭,都是儿子应该做到的。儿子相当于一个Java类,直接申明儿子对象,在后续方法中调用。
class TravelerTian{
// 技能:万物归一
public void skillWanwuGuiyi(String AKey,String hurt){
System.out.println(hurt);
};
}
class TravelerKong extends TravelerTian{
public void doRequest(){
super.skillWanwuGuiyi("1","123");
}
}
/**
*
* 某天你收到用户差评,要求你把钟离伤害拉高,糟糕的是,你写了继承关系
* 该死,你必须要在父类中添加方法,可是一旦添加方法
* 子类必须继承一个没有任何用处的方法,造成代码的耦合性
* 为此,你必须将继承关系改写为组合关系
* 正因为父类是抽象类
*
*/
class TravelerKong {
@注入
private TravelerTian travelerTian;
public void doRequest(){
travelerTian.skillWanwuGuiyi("1","123");
}
}
- 迪米特法则:一个类减少其他类的业务,通过引入第三类调用该类的业务,要是一个人每天的日常全部编入程序,吃饭睡觉工作学习娱乐,这些每天都发生,可是又有点不同,你不可能将每天都总结在一个Java类中,那会有无数的Java类,这时你就需要把吃饭睡觉放入单独的Java类,完全独立的事件,吃饭是吃饭,睡觉是睡觉,你不能把这两件事混为一谈,所以他们自然成为两个对象,当需要汇总一天的事情时,主类才会调用这个对象,将对象属性重新定义睡觉的姿势,吃饭的过程。
class MyWordGame { // 现实 虚拟 大脑 // 游戏要远离现实世界 public void fleeReality(){} // 游戏要进入虚拟世界 public void entrySuppositional(){} // 大脑要分辨现实和虚拟 public void brainDiscriminateRAE(){} } /** * * 仔细想想,这三个的关系,一定大脑在前,现实在后,虚拟在末尾 * 三者不能同时进行,必定有多层处理,需要重新将包结构建立 * 以前都是在同一个包内 * */ com.hikktn.reality com.hikktn.suppositional com.hikktn.brain 继续进行业务细化 com.hikktn.reality.service com.hikktn.reality.dao com.hikktn.reality.controller 与此类推 ……