针对接口编程,真正的意思是“针对超类编程”(接口通常是一个抽象类或者是一个接口)。
例子:
针对现实编程:
Dog dog=new Dog();
dog.bark();
针对接口/超类编程
Animal animal=new Dog();
animal.bark();
更棒的是,子类实例化的动作不再需要在代码中硬编码。
Animal animal=getAnimal();
animal.bark();
在编译期间,我们无法知道实际的子类型是什么,我们只关心它是如何bark的就行了。
在运行时,我们可以set子类型,从而动态的执行具体的子类方法。
这种编程思想很多,比方说:日志,我们只针对接口编程,具体子类型,在运行时才知道。
private static final Logger log = LoggerFactory.getLogger(ArticleManagerImpl.class);
log.error("EZ编程网-面向接口编程");
具体log的实现,要在运行期间才知道。
策略模式的例子:
人:男人、女人、木头人、机器人。
人会站立、走路、说话。
男人会站立、走路、说话。
女人会站立、走路、说话。
木头人会站立、不会走路、不会说话。
机器人会站立、会走路、不会说话。
单纯的继承,已经不能满足需求,我们需要把会变的提取出来,不变的继承下去。
如:所有人都会站立,所以站立可以采用继承。
但是说话和走路并不是所有人都会,所以要把这些会变的,放到运行时,动态的解决。
这里走路和说话就是人的策略,
不同的人可以使用不同的策略,如稻草人使用不会说话的策略。
第一种实现方式,编译时解决,写走路和说话两个接口,让男人女人再实现这两个接口,机器人再实现走路接口。
这种方式,增加代码量,而且不容易维护。
第二种实现方式,运行时解决,采用策略模式实现:运行时,想改变人的行为,只需要调用人的setter方法就可以了。
大家要深入理解下面这段话:
把站立和说话这些不确定的方法做成接口组合进来,使用接口编程完成站立和说话的方法内容。分别实现接口,在运行时,动态的把接口的实现setter进来就可以了,这样子类继承到的站立和说话方法就会随着动态setter的变化而变化。
我们把人走路和说话行为想成“一族算法”。
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。这就是策略模式。
package com.ez.impl;
import com.ez.Human;
/**
人:男人、女人、稻草人、机器人
所有人会站立。
男人会站立、走路、说话。
女人会站立、走路、说话。
稻草人会站立、不会走路、不会说话。
机器人会站立、会走路、不会说话。
每个人都有自己的外观。
* @author 窗外赏雪
*
*/
public class Test {
public static void main(String[] args) {
System.out.println("============稻草人=============");
Human scarecrow=new Scarecrow();
scarecrow.speak();
scarecrow.walk();
scarecrow.display();
scarecrow.stand();
System.out.println("============机器人=============");
Human android=new Android();
android.speak();
android.walk();
android.display();
android.stand();
System.out.println("============男人=============");
Human man=new Man();
man.speak();
man.walk();
man.display();
man.stand();
System.out.println("============女人=============");
Human women=new Women();
women.speak();
women.walk();
women.display();
women.stand();
}
}
package com.ez;
/**
* 人:会站立、走路、说话。
* @author 窗外赏雪(EZ编程网)
*
*/
public abstract class Human {
/**
* 每个人都有说话和走路的行为,人是通过组合得到这两个行为的。
* 我们应该多用组合少用继承。
*/
protected SpeakBehavior speakBehavior;
protected WalkBehavior walkBehavior;
/**
* 不同类别的人,说话方式不同,如稻草人跟机器人都不会说话。
* 把编译期间不确定的,用接口编程。
*/
public void speak(){
speakBehavior.speak();
}
/**
* 不同类别的人,走路方式不同,如稻草人不会走路。
* 把编译期间不确定的,用接口编程。
*/
public void walk(){
walkBehavior.walk();
}
/**
* 每种类别的人,表现出来都不一样,所以用抽象方法。
*/
public abstract void display();
/**
* 所有人都会站立,所以在超类中实现,这样所有的子类,都会站立。
*/
public void stand(){
System.out.println("只要是人,都会站立");
}
}
package com.ez.impl;
import com.ez.Human;
public class Android extends Human{
/**
* 在运行时,动态创建子类。
* 机器人不会说话、会走路
*/
public Android() {
speakBehavior=new SpeakNoWay();
walkBehavior=new WalkWithLeg();
}
@Override
public void display() {
System.out.println("android dispaly");
}
}
package com.ez.impl;
import com.ez.Human;
public class Women extends Human{
/**
* 在运行时,动态创建子类。
* 女人会说话、会走路
*/
public Women() {
speakBehavior= new SpeakWithMouth();
walkBehavior = new WalkWithLeg();
}
@Override
public void display() {
System.out.println("women display");
}
}
package com.ez.impl;
import com.ez.Human;
public class Man extends Human{
/**
* 在运行时,动态创建子类。
* 男人会说话、会走路
*/
public Man() {
speakBehavior=new SpeakWithMouth();
walkBehavior=new WalkWithLeg();
}
@Override
public void display() {
System.out.println("man display");
}
}
package com.ez.impl;
import com.ez.Human;
/**
* 稻草人也是人
* @author 窗外赏雪
*
*/
public class Scarecrow extends Human{
/**
* 在运行时,动态创建子类。
* 稻草人人不会说话、不会走路
*/
public Scarecrow() {
speakBehavior=new SpeakNoWay();
walkBehavior=new WalkNoWay();
}
@Override
public void display() {
System.out.println("scarecrow display");
}
}
package com.ez;
public interface SpeakBehavior {
/**
* 说话
*/
void speak();
}
package com.ez.impl;
import com.ez.SpeakBehavior;
/**
* 这是说话行为的实现,给不会说话的人使用。
* @author 窗外赏雪
*
*/
public class SpeakNoWay implements SpeakBehavior{
@Override
public void speak() {
System.out.println("sorry I can't speak");
}
}
package com.ez.impl;
import com.ez.SpeakBehavior;
/**
* 这是说话行为的实现,给会说话的人使用。
* @author 窗外赏雪
*
*/
public class SpeakWithMouth implements SpeakBehavior{
@Override
public void speak() {
System.out.println("I can speak");
}
}
package com.ez;
public interface WalkBehavior {
/**
* 走路
*/
void walk();
}
package com.ez.impl;
import com.ez.WalkBehavior;
/**
* 这是走路行为的实现,给不会走路的人使用。
* @author 窗外赏雪
*
*/
public class WalkNoWay implements WalkBehavior{
@Override
public void walk() {
System.out.println("I can't walk");
}
}
package com.ez.impl;
import com.ez.WalkBehavior;
/**
* 这是走路行为的实现,给会走路的人使用。
* @author 窗外赏雪
*
*/
public class WalkWithLeg implements WalkBehavior{
@Override
public void walk() {
System.out.println("I can walk");
}
}