写点什么

架构师训练营 第二周 学习心得

用户头像
李君
关注
发布于: 2020 年 06 月 17 日
架构师训练营 第二周 学习心得

一,软件设计的“臭味”



  • 僵化性

  • 脆弱性

  • 牢固性

  • 粘滞性

  • 不必要的复杂性

  • 不必要的重复性



二,软件设计的最终目的



  • 易扩展

  • 健壮性

  • 可移植

  • 易维护



三,设计模式概述



1. 开/闭原则(OCP)



  • 一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。

  • 开闭原则告诉我们应尽量通过扩展软件实体的行为来实现变化,而不是通过修改现有代码来完成变化,它是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。



策略模式



定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。

示意图
优点



  • 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。

  • 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。

  • 使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。

缺点



  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。

  • 由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。可以通过使用享元模式在一定程度上减少对象的数量。



适配器模式



将一个类的接口变换成客户端期待的另一种接口,从而使得原本因接口不匹配而无法在一起工作的两个类能够在一起工作



示意图





优点
  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。

  • 增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用。

  • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

缺点
  • 一次最多只能适配一个适配者类,不能同时适配多个适配者。

  • 目标抽象类只能为接口,不能为类,其使用有一定的局限性。

观察者模式



观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。



观察者模式 = 出版者 + 订阅者

示意图
优点
  • 观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息传递机制,并抽象了更新接口,使得可以有各种各样的表示层充当具体的观察者角色。

  • 观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察者对象只需要维持一个抽象观察者的集合,无需了解其具体观察者。

  • 观察者模式支持广播通信,观察目标会向所有已注册的观察者发送通知,降低了一对多系统的设计难度。

  • 观察者模式满足开闭原则的要求,增加新的具体观察者无须修改原有的系统代码。

缺点
  • 如果一个观察目标对象有很多的直接观察者和间接观察者,那么所有的观察者接收到消息会耗费大量的时间。

  • 如果观察者和被观察者之间存在循环依赖,那么观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道目标观察对象发生了变化。



2. 依赖倒置 (DIP)



高层模块不应该依赖于低层模块,两者应该都依赖于抽象。 抽象不应该依赖于细节,细节应该依赖于抽象。

示意图
特点

依赖倒置正式通过对高层的抽象,让底层去实现高层的抽象的接口,从而摆脱对底层模块的依赖,从而实现了高层模块的重用。

3. Liskov替换原则 (LSP)



如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换为o2,程序P的行为没有发生变化,那么类型S是类型T的子类型。



子类型(subtype)必须能够替换掉它们的基类型(base type)

四个原则
1. 子类必须完全实现父类的方法

例子

枪支抽象类:

public abstract class AbstractGun{
//枪支射击的方法
public abstract void shoot();
}



手枪,步枪 的实现类:

public class Handgun extends AbstractGun{
public void shoot(){
System.out.println("手枪射击...");
}
}



public class Rifle extends AbstractGun{
public void shoot(){
System.out.println("步枪射击...");
}
}



士兵实现类:

public class Soldier{
private AbstractGun gun;
public void setGun(AbstractGun gun){
this.gun = gun;
}
public void killEnemy(){
System.out.println("士兵开始射击...");
this.gun.shoot();
}
}



场景类:

public class Client{
public static void main(Strings[] args){
Soldier soldier = new Soldier();
//设置士兵手握手枪
soldier.setGun(new Handgun());
soldier.killEnemy();
//设置士兵手握步枪
soldier.setGun(new Rifle());
soldier.killEnemy();
}
}
2. 子类可以有自己的个性

例子

AUG狙击步枪:

public class AUG extends Rifle {
public void zoomOut(){
System.out.println("通过放大镜观察");
}
public void shoot(){
System.out.println("AUG射击...");
}
}



狙击手类:

public class Snipper{
public void killEnemy(AUG aug){
aug.zoomOut();
aug.shoot();
}
}



场景类:

public class Client{
public static void main(Strings[] args){
Snipper snipper = new Snipper();
snipper.killEnemy(new AUG());
}
}
3. 覆盖或实现父类的方法时输入参数可以被放大

例子

先定义一个父类:

public class Father{
public Collection doSomething(HashMap map){
System.out.println("父类被执行");
return map.values();
}
}



再定义一个子类:

public class Son extends Father{
public Collection doSomething(Map map){
System.out.println("子类被执行");
return map.values();
}
}



场景类:

public class Client{
public static void main(Strings[] args){
//父类存在的地方,子类应该可以存在
Father father = new Father();
HashMap map = new HashMap();
father.doSomething(map);
}
}



4. 覆盖或实现父类的方法时输出结果可以被缩小
  • 父类的一个方法的返回值是一个类型T,子类的相同方法的返回值为S,那么里氏替换原则就要求S必须小于等于T。

  • 采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类还可以继续运行。在实际项目中,每个子类对应不同的业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑,非常完美。

4. 单一职责原则 (SRP)

应该有且仅有一个原因引起类的变更。

示意图



特点
  • 类的复杂性降低,实现上面职责都有清晰明确的定。

  • 可读性提高,复杂性降低

  • 可维护性提高

5. 接口分离原则 (ISP)

客户端不应依赖它不需要的接口;类间的依赖关系应该建立在最小的接口上。



示意图



特点
  • 不要在一个接口里面放很多的方法,这样会显得这个类很臃肿。

  • 接口应该尽量细化,一个接口对应一个功能模块,同时接口里面的方法应该尽可能的少,使接口更加灵活轻便。

  • 接口隔离原则要求"尽量使用多个专门的接口"专门提供给不同的模块。

发布于: 2020 年 06 月 17 日阅读数: 55
用户头像

李君

关注

结硬寨,打呆仗。 2018.09.11 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营 第二周 学习心得