策略设计模式
what:概念
定义了算法族,分别封装起来,让他们之间可以互相替换,
此模式让算法的替换独立于使用算法的客户。
(这里的算法就是一个个行为-方法)
1. 继承的弊端
-
首先使用继承来设计接口是一种很糟糕设计方法,因为软件总是存在变化的,使用继承很难应对改变,因为父类的改变会改变所有的子类
-
在需求变化中,会出现并不是所有的子类都需要基类的方法,这样就违反类里氏代换原则。
2. 引子
- 找出应用中可能需要变化之处,并将它独立出来,不要和那些不变化的代码混合在一起。
2.1 依赖倒转原则(针对接口编程真正的意义是针对超类型编程)
-
所谓超类,我们常用的就是接口了,还有基类,抽象类。
-
简而言之就是我实际操作是只操作这些超类,并不直接操作具体实现类。
2.1.1 个人理解
- 设计中,要让设计更加有弹性。有弹性的前提是在一开始设计时就不要写死,留出更所的可变空间。面向接口编程刚好能提供这样的弹性空间。
-
提供弹性的很直观的方法就是组装一个类。和现实中的组装一样,一个牌子的电脑,显卡好但cup不好,主板好但内存差。反正就是不符合我们的要求。
-
那怎么办,我们可以自己买 主板 ,显示器,显卡,内存,主机来组装我们自己的电脑,这样就能满足我们的需求。
-
软件设计的装也一样,我们的材料就是接口了,通过使用不同的接口来组装我们的类。(接口:就相当于:主板,显示器…)(不同接口的实现类:相当于主板有不同厂家,显示器有三星,戴尔…)
-
还有最终要的一点,我们组装的类不实现任何接口,都是用每个接口的实现类来进行组装。(相当于富士康不造零件,它只搞组装一样)。不绑死才会更灵活,这样才会有弹性。
2.1.2 疑问
都说针对接口编程而不针对实现编程,但是有时候实现类会拓展接口的,导致接口实现类中的某些方法并不在接口中。这样就不能通过接口编程了,该如何解决这个问题呢?
2.1.3 关于组装的代码示例
- 接口组装
//鸭子接口
public interface Duck {
public void swim();
public void display();
}
//红色鸭子组装类
public class RedDuck implements Duck {
public void swim() {
System.out.println("是鸭子都会游泳!");
}
public void display() {
System.out.println("我是红色的!");
}
}
//蓝色鸭子组装类
public class BlueDuck implements Duck {
public void swim() {
System.out.println("所有鸭子都会游泳!");
}
public void display() {
System.out.println("我是蓝色的!");
}
}
//测试类
public class mainTest {
public static void main(String[] args) {
System.out.println("红色鸭子~~~~~~~~~~~");
Duck duck= new RedDuck();
duck.swim();
duck.display();
System.out.println("蓝色鸭子~~~~~~~~~~~");
Duck duck1= new BlueDuck();
duck1.swim();
duck1.display();
}
}
//运行结果
红色鸭子~~~~~~~~~~~
是鸭子都会游泳!
我是红色的!
蓝色鸭子~~~~~~~~~~~
所有鸭子都会游泳!
我是蓝色的!
- 继承
//颜色接口
public interface ChangeColor {
public void color();
}
//颜色接口实现类01-红色
public class RedColor implements ChangeColor {
public void color() {
System.out.println("我是红色的!");
}
}
//颜色接口黑色实现类
public class BlackColour implements ChangeColor {
public void color() {
System.out.println("我是黑色的!");
}
}
//颜色接口实现类02-蓝色
public class BlueColou implements ChangeColor {
public void color() {
System.out.println("我是蓝色的!");
}
}
//鸭子基类
public class Duck01 {
//这里私有变量,子类是无法继承的
public ChangeColor changeColor;
public void swim() {
System.out.println("所有鸭子都会游泳!");
}
//展示鸭子颜色
public void performColor(){
changeColor.color();
}
//改变颜色接口
public void setClour(ChangeColor clour){
changeColor=clour;
}
}
//继承鸭子基类的黑鸭子
public class BlackDuck extends Duck01 {
public BlackDuck() {
changeColor= new BlackColour();
}
}
//测试类
//将颜色的具体实现类注入到展示方法中,可以任意改变鸭子颜色,很灵活
public class mainTest {
public static void main(String[] args) {
System.out.println("黑色鸭子~~~~~~~~~~~");
Duck01 duck2= new BlackDuck();
duck2.swim();
duck2.performColor();
//改变鸭子颜色
duck2.setClour(new RedColor());
duck2.performColor();
}
}
//结果:
所有鸭子都会游泳!
我是黑色的!
鸭子换色~~~~~~~~~~~
我是红色的!
2.1.4 组装总结
-
该组装类中,颜色是用了接口+外部实现类来进行组装,通过提供的改变鸭子颜色方法,可以随意的改变鸭子的颜色,在改变颜色这里弹性高
-
继承的话,基类定义所有的鸭子都会游泳,但后期需求变更,加入了铁鸭子,铁鸭子不会游泳的。这就体现了继承的不足,要修改的话就要修改鸭子基类了,这又违背了里氏代换原则。
-
组装的疑问:是不是所有的方法都要定义单独的接口呢?其实不是的,只有哪些会发生变化的。
-
由上面代码可知,继承有很大的缺点,使用外部接口组合(组装)更具灵活性。这也体现多用组合,少用继承的设计原则
单例模式
个人理解
- 单例模式如名字而言,就是该类只有一个示例对象。
why :为什么要使用单例模式
-
使用单例模式,意味着只能有一个实例来提供服务。计算机中有的业务是必须只能有一个实例来的。
-
如:网站计数,window系统的任务管理器,线程池,数据库的连接池。这些都是只允许一个实例存在
how :怎么实现单例模式
1. 单例模式结构
- 单例类