设计原则
1、找出应用中的可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
2、针对接口编程而不是针对实现编程
3、多用组合,少用继承
核心思想是针对接口编程,将可能改变的功能设计成接口,具体有多少可能的功能都可以是实现类,这样依靠接口回调就可以达到极低耦合性
结合问题理解
创造一个鸭子游戏,鸭子有两个特征,飞和叫。
而问题在于有些鸭子会飞,有些不会飞;有些会叫,有些不会叫。
这时对设计有挑战:
简单使用继承+重写:那么你可能陷入无穷尽的鸭子类型的拓展方法的重写中。如果父类定义的是会飞会叫。那么建立会飞不会叫你需要重写“叫”方法;如果建立会叫不会飞你需要重写“飞”方法;如果不会叫不会飞。。。。。这显然不是绝佳的设计。
简单使用接口(抽象)的方式:那么同样你会陷入无穷尽的方法的实现中。将“飞”和“叫”方法抽象出来,在面对不同的鸭子时采用不同的实现,这显然是极度增加代码量的方式。
真正的解决方式是(分开变化和不会变化的部分):
针对接口编程而不是普通的使用接口(拆出变化部分)
将使用的功能定义成接口(例子中的飞和叫),并将不同的具体实现类实现
这时鸭子类不会负责实现功能接口,有上述的其他类来实现,我们称为“行为类”,使用这种方式拆分了“对象类”和“行为类”
这样在真正的鸭子对象中就可以利用接口回调来找到真正实现
你还是需要一个父类(不变化部分)
让子类拥有共同的属性和方法
定义功能接口
public interface FlyBehavior {
public void fly();
}
功能实现(每个不同功能可实现一个如会飞和不会飞,在此不举例只实现飞和叫各一个)
public class Fly implements FlyBehavior{
public void fly() {
System.out.println("可以飞");
}
}
公共父类Duck的编写,定义了鸭子都有飞和叫的形态
重点在于对接口的声明,Duck应该有你抽象拆分出去的接口类型的变量的属性,以便以后在继承中使用接口回调
其余公共部分
我们还应该注意到对象的动态拓展性可以添加set方法来使你可以在main中以“注入”的形式修改功能
我们建立一个具体对象绿头鸭来测试,其会飞叫声是嘎嘎嘎
我们已经实现会飞实现类是Fly,嘎嘎嘎的叫声是Quack
main执行
最后的动态注入只需传入相应的实现类
由此我们最终完成了对可能改变的功能的拆分 ,通过针对接口编程的方式,成功将具体功能拆出成为具体实现类,并且通过多态思想(接口回调)执行对应功能
网友评论