设计模式 里氏替换原则
继续里氏替换原则。
上回栗子为正方形不能被长方形继承,这次,具体
子类必须实现父类的方法
类图
对具体代码进行实践
// 定义抽象类枪
public abstract class AbstractGun{
// 定义枪
public abstract void shoot();
}
// 定义手枪,步枪,机枪
public class Handgun extends AbstractGun{
// 定义手枪
public void shoot(){
}
}
public class Rifle extends AbstractGun{
public void shoot(){
}
}
public class MachineGun extends AbstractGun{
public void shoot(){
}
}
接着拥有枪,定义士兵
public class Soldier{
// 让其获得具体的枪的对象
private AbstractGun gun;
// 给其一把枪
public void setGun(AbstractGUn _gun){
this.gun = _gun;
}
// 定义杀敌的行为
public void killEnemy(){
gun.shoot(); // 使用对象的shoot方法
}
}
最后定义整个场景
public class Client{
public static void main(String[] args){
// 产生士兵
Soldier sanMao = new Soldier();
// 给其一只枪
sanMao.setGun(new Rifle());
// 杀敌
sanMao.killEnemy();
}
}
在场景中,三毛需要什么枪支,就直接new 出一个枪支即可,然后其内通过抽象类获取到对象,然后对齐进行修饰
装饰器模式
更改枪支
如果要更改枪支,直接增加新的类即可
由于玩具枪不能射击,所以代码如下
public class ToyGun extends AbstractGun {
public void shoot(){
}
}
对参加进行修改
public class Client{
public static void main(String[] args){
Soldier sanMao = new Soldier();
sanMao.setGun(new ToyGun());
sanMao.killEnemy();
}
}
由于之前在士兵类中定义了shoot方法,导致三毛杀敌,业务出现问题
解决,只能再次定义一个新的玩具枪的抽象类和强的抽象类之间存在泛化关系
子类可以拥有行为和外观
对步枪继续继承一些类,该类更加详细
实现以下AUG类
public class AUG extends Rifle {
// 对阻击枪设置一个望远镜
public void zoomOut(){
}
// 重写父类的射击方法
public void shoot(){
}
}
需要增加阻击手和阻击枪之间存在组合关系
uml图如下
实现阻击手
public class Snipper{
public void killEnemy(AUG _ang){
_ang.zoomOut(); // 先查看情况
// 射击
ang.shoot();
}
}
这就可以啦。在场景中可以杀死敌人
public class Client{
public static void main(String[] args){
Snipper sanMao = new Snipper();
sanMao.setRiffle(new AUG); // 给三毛一只枪
sanMao.killEnemy(); // 进行设计
}
}
这里直接将子类传递进入。
Java中向下转型不安全
public class Client{
public static void main(String[] args){
Snipper sanMao = new Snipper();
sanMao.setRiffle(new AUG); // 给三毛一只枪
sanMao.killEnemy(); // 进行设计
}
}
好吧,在子类出现的地方,父类未必就可以出现。。。向下强制转型,不安全
覆盖或实现父类的方法时输入参数可以被放大
里式替换原则要求定义一个契约,即父类或接口,即契约设计。
// 定义一个转换类
public class Father{
public Collection doSomething(HashMap map){
return map.values();
}
}
这个类完成转换
然后定义子类
public class Son extends Father {
// 将输入放大
public Collection doSomething(Map map){
return map.value();
}
}
然后接着使用
public class Client{
public static void main(String args){
// new 出父类
Father f = new Father();
HashMap map = new HashMap();
f,doSOmething(map);
}
}
在上方中父类被执行
根据里氏替换原则,子类能替代父类
public class Client{
public static void main(String[] args){
SOn f = new Son();
HashMap map = new HashMao();
f.doSomething(map);
}
}
上方的即为里氏替换原则。
子类代替父类传入,子类永远不会被执行。子类要运行,必须重写父类。或者是参数的范围更宽
举例子,如果父类参数条件大,子类参数条件小
public class Father{
public Collection doSomething(Map map){
return map.values();
}
}
public class Son extends Father{
public Collection doSomething(HashMap map){
return map.values();
}
}
接着运行
public class Client{
public static void main(String[] args){
Father f = new Father();
HashMap map = new HashMap();
f.doSomething(map);
}
}
此时可以运行
根据里氏替换原则,子类能使用的地方,父类也能使用。
public class Client{
public static void main(String[] args){
Son f = new Son();
HashMap map = new HashMap();
f.doSomething(map);
}
}
子类被执行,
总结
重载实现父类的时候,输入的参数要求放大
重写,实现父类的时候可以缩小。
www.iming.info