前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式 里氏替换原则

设计模式 里氏替换原则

原创
作者头像
mySoul
发布2018-11-25 04:45:19
4760
发布2018-11-25 04:45:19
举报
文章被收录于专栏:mySoulmySoul

设计模式 里氏替换原则

继续里氏替换原则。

上回栗子为正方形不能被长方形继承,这次,具体

子类必须实现父类的方法

类图

对具体代码进行实践

代码语言:txt
复制
// 定义抽象类枪
public abstract class AbstractGun{
	// 定义枪
	public abstract void shoot();
}
代码语言:txt
复制
// 定义手枪,步枪,机枪
public class Handgun extends AbstractGun{
	// 定义手枪
	public void shoot(){
	}
}
public class Rifle extends AbstractGun{
	public void shoot(){
	}
}
public class MachineGun extends AbstractGun{
	public void shoot(){
	}
}

接着拥有枪,定义士兵

代码语言:txt
复制
public class Soldier{
	// 让其获得具体的枪的对象
	private AbstractGun gun;
	// 给其一把枪
	public void setGun(AbstractGUn _gun){
		this.gun = _gun;
	}
	// 定义杀敌的行为
	public void killEnemy(){
		gun.shoot();	// 使用对象的shoot方法
	}
}

最后定义整个场景

代码语言:txt
复制
public class Client{
	public static void main(String[] args){
		// 产生士兵
		Soldier sanMao = new Soldier();
		// 给其一只枪
		sanMao.setGun(new Rifle());
		// 杀敌
		sanMao.killEnemy();
	}
}

在场景中,三毛需要什么枪支,就直接new 出一个枪支即可,然后其内通过抽象类获取到对象,然后对齐进行修饰

装饰器模式

更改枪支

如果要更改枪支,直接增加新的类即可

由于玩具枪不能射击,所以代码如下

代码语言:txt
复制
public class ToyGun extends AbstractGun {
	public void shoot(){
	}
}

对参加进行修改

代码语言:txt
复制
public class Client{
	public static void main(String[] args){
		Soldier sanMao = new Soldier();
		sanMao.setGun(new ToyGun());
		sanMao.killEnemy();
	}
}

由于之前在士兵类中定义了shoot方法,导致三毛杀敌,业务出现问题

解决,只能再次定义一个新的玩具枪的抽象类和强的抽象类之间存在泛化关系

子类可以拥有行为和外观

对步枪继续继承一些类,该类更加详细

实现以下AUG类

代码语言:txt
复制
public class AUG extends Rifle {
	// 对阻击枪设置一个望远镜
	public void zoomOut(){
	}
	// 重写父类的射击方法
	public void shoot(){
	}
}

需要增加阻击手和阻击枪之间存在组合关系

uml图如下

实现阻击手

代码语言:txt
复制
public class Snipper{
	public void killEnemy(AUG _ang){
		_ang.zoomOut();	// 先查看情况
		// 射击
		ang.shoot();
	}
}

这就可以啦。在场景中可以杀死敌人

代码语言:txt
复制
public class Client{
	public static void main(String[] args){
		Snipper sanMao = new Snipper();
		sanMao.setRiffle(new AUG);	// 给三毛一只枪
		sanMao.killEnemy();	// 进行设计
	}
}

这里直接将子类传递进入。

Java中向下转型不安全

代码语言:txt
复制
public class Client{
	public static void main(String[] args){
		Snipper sanMao = new Snipper();
		sanMao.setRiffle(new AUG);	// 给三毛一只枪
		sanMao.killEnemy();	// 进行设计
	}
}

好吧,在子类出现的地方,父类未必就可以出现。。。向下强制转型,不安全

覆盖或实现父类的方法时输入参数可以被放大

里式替换原则要求定义一个契约,即父类或接口,即契约设计。

代码语言:txt
复制
// 定义一个转换类
public class Father{
	public Collection doSomething(HashMap map){
		return map.values();
	}
}

这个类完成转换

然后定义子类

代码语言:txt
复制
public class Son extends Father {
	// 将输入放大
	public Collection doSomething(Map map){
		return map.value();
	}
}

然后接着使用

代码语言:txt
复制
public class Client{
	public static void main(String args){
		// new 出父类
		Father f = new Father();
		HashMap map = new HashMap();
		f,doSOmething(map);
	}
}

在上方中父类被执行

根据里氏替换原则,子类能替代父类

代码语言:txt
复制
public class Client{
	public static void main(String[] args){
		SOn f = new Son();
		HashMap map = new HashMao();
		f.doSomething(map);
	}
}

上方的即为里氏替换原则。

子类代替父类传入,子类永远不会被执行。子类要运行,必须重写父类。或者是参数的范围更宽

举例子,如果父类参数条件大,子类参数条件小

代码语言:txt
复制
public class Father{
	public Collection doSomething(Map map){
		return map.values();
	}
}
代码语言:txt
复制
public class Son extends Father{
	public Collection doSomething(HashMap map){
		return map.values();
	}
}

接着运行

代码语言:txt
复制
public class Client{
	public static void main(String[] args){
		Father f = new Father();
		HashMap map = new HashMap();
		f.doSomething(map);
	}
}

此时可以运行

根据里氏替换原则,子类能使用的地方,父类也能使用。

代码语言:txt
复制
public class Client{
	public static void main(String[] args){
		Son f = new Son();
		HashMap map = new HashMap();
		f.doSomething(map);
	}
}

子类被执行,

总结

重载实现父类的时候,输入的参数要求放大

重写,实现父类的时候可以缩小。

www.iming.info

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 子类必须实现父类的方法
    • 更改枪支
    • 子类可以拥有行为和外观
    • 覆盖或实现父类的方法时输入参数可以被放大
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档