设计模式学习笔记

3 篇文章 0 订阅

学习设计模式的小随笔:)

我们为什么要采取设计模式

在《Head First设计模式》中,通过鸭子的例子展示了出来;
我们新建Duck类,制定Duck应该有的行为,如果把所有的行为都直接写在Duck下面:

  • quack() 叫
  • swim() 游泳
  • display() 样貌
  • fly() 飞行,问题也就出在这里

问题: 各种鸭子通过继承 Duck类实现,如果我们的子类都是真正的鸭子当然没问题,如果此时我们新建一个橡皮鸭,它并不会飞,但是却继承到了fly()
在这里插入图片描述
如果通过接口解决,将fly( )从超类中提取出来,放进Flyable接口,会飞的鸭子才要去实现接口,同理Quackable接口,因为我们会遇到木头鸭又不会叫又不会飞;
在这里插入图片描述
问题: 笨蛋主意,J由于ava接口是不能写函数内容的,这样一来没有fly( ), quack( )代码可以复用了,如果我们要写48个会飞的Duck子类,就要重新写48次fly( );

设计原则:找出应用中可能需要变化之处,将其独立出来,与不需要变化的代码分离

fly, quack需要从Duck中分离开来,我们将其分别新建Fly类Quack类
在这里插入图片描述

而Fly如果单独作为独立的类又涉及了怎么飞,因为但凡涉及到飞的动作都可以在这里实现,比如用翅膀飞、火箭飞行、不会飞,为了使我们的设计更具有弹性,我们将Fly设定成接口<interface> FlyBehavior,其中含有抽象函数fly( ),具体的实现再通过新建类FlyWithWings、FlyNoWay去实现接口。同理QuackBehavior
在这里插入图片描述

设计原则:针对接口(超类型)编程,而不是针对实现编程

如果按照Duck超类内写fly( ),或者是子类去继承某个接口再自行实现fly( )方法,这样都过度依赖于实现

针对接口(超类型)编程,更明确的说是变量的声明类型应该是超类型(通常是一个抽象类或者是一个接口)。如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量(类似向上转型,是这个意思吧);

通过猫狗实例说明:
在这里插入图片描述
如果针对实现编程,声明变量详细到子类,必须使用具体的实现编码,Dog类的实例只能bark()

Dog d = new Dog();
d.bark();

如果是针对接口/超类型编程,我们知道声明的对象是狗,但是利用了animal的多态调用,子类的实例化动作不需要再代码中硬编码,而是在运行时才指定具体的实现对象:

Animal animal = new Dog();
animal.makeSound();

这样我们就不用关心实际的子类型是“什么“了,只需要关心如何进行抽象类中的makeSound()就好了;

鸭子总结

为了实现鸭子的FlyQuack,我们独立了两个接口FlyBehaviorQuackBehavior,之后再通过具体的类去实现具体的行为。
这样的设计可以让飞行呱呱叫的动作被其他类型的对象复用,既有了继承的复用好处,也没有继承所带来的包袱
在这里插入图片描述

-21.7.15

Duck类中引入成员变量:声明为“接口类型”的行为Flybehavior flyBehavior, QuackBehavior quackBehavior。再加上进行行为的两个行为函数performQuack(), performFly()替代fly(), quack();
在这里插入图片描述
Duck类编写:

public abstract class Duck {
	//接口成员
	FlyBehavior flyBehavior;
	Quackbehaior quackbehavior;
	public Duck() {
	}

	public abstract void display();

	public void performFly() {
		flyBehavior.fly();
	}

	public void performQuack() {
		quackBehavior.quack();
	}

	public void swim() {
		System.out.println("All ducks float, even decoys!");
	}
}

MallardDuck子类编写:

public class MallardDuck extends Duck {
	public MallardDuck() {
		//因为MallardDuck子类继承自Duck类,具有Duck类中的flyBehavior与quackBehavior实例变量;
		//在这里子类的具体特性赋值进去;
		quackBehavior = new Quack();
		flyBehavior = new FlyWithWings();
	}
	public void display() {
		System.out.println("I'm a real Mallard duck!");
	}
}

MallardDuck绿头鸭子他的叫声可能是“呱呱叫”,不是”吱吱叫“或者“不会叫”,这个是在MallardDuck实例化时,构造器函数将具体的实现类FlyWithWings赋值进去;

飞行接口及具体实现类:

public interface FlyBehavior {
	public void fly();
}
public class FlyWithWings implements FlyBehavior {
	public void fly() {
		System.out.println("I'm flying!!");
	}
}
public class FlyNoWay implements FlyBehavior {
	public void fly() {
		System.out.println("I can't fly");
	}
}

Quark接口及具体实现类:

public interface QuackBehavior {
	public void quark();
}
public class Quack implements QuackBehavior {
	public void quack() {
		System.out.println("Quack");
	}
}
public class MuteQuak implements QuackBehavior {
	public void quark() {
		System.out.println("<< Silence >>");
	}
}
public class Squeak implements QuackBehavior {
	public void quark() {
		System.out.println("Squeak!!");
	}
}

测试类:

public class MiniDuckSimulator {
	public static void main(String[] args) {
		//声明类是超类Duck,实现类才是具体类;
		//并且由于子类的构造函数,接口成员已经被具体实现类赋值:quackBehavior = new Quack(),flyBehavior = new FlyWithWings();
		Duck mallard = new MallardDuck();
		mallard.performQuack();
		mallard.performFly();
	}
}

运行起来:
在这里插入图片描述

调用示意图:在这里插入图片描述
-21.7.16

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值