program 3 工厂设计模式、类的继承
概述
《第一行代码 JAVA》的 4.7.3 接口的应用——工厂设计模式(Factory) 提到:“ 在客户端的操作上取消关键字new的使用,而使用Factory.getInstance()方法取得接口实例化对象,这时客户端不再需要关注具体子类,也不需要关注Factory类是怎么处理的,只需关注如何取得接口对象并且操作。 ”
可见,“客户端取消关键字new的操作”、“隐藏程序具体实现”、“客户端只看到接口” 是工厂设计模式的要点。
构造这样一个程序:客户端通过接口可以查询某样东西(Sth)能怎好(能吃吗?怎么吃?好吃吗?)。
仿造书中的图例,我也绘制了对应的逻辑框图如下。为了同时对比类的继承的特点,Sth接口 implements 在动物类 和 extends在植物接口上;动物类被Pig类和Bat类所继承;植物接口则被Grass类和Apple类应用。动物类这一支线体现了类的继承;植物接口这边则体现接口的继承和拓展。
经过调试,得到的一些小结有:
- 工厂设计模式中,能够调用的方法是所使用的接口中定义的类。比如说,① 如果用Sth接口取得实例化对象,那么就可以调用getInfo()、howToEat()等方法,而不能调用植物接口中的 color() 方法,尽管草类和苹果类继承了植物接口。② 如果用Plant接口取得实例化对象,就能够调用 color() 方法了。
- 接口的扩展,使用extends,继承上一个接口的所有抽象方法和全局变量。比如 interface Plant extends Sth{ }
- 接口的应用,使用implements,继承接口的抽象方法。比如 public class Animal implements Sth { }
- 类的继承,使用extends,继承上一个类的所有方法和变量。比如 public class Bat extends Animal { }
- 接口中的抽象方法,在应用的类中一定要覆写。
- 接口虽然更符合工厂设计模式的要求,但是接口中只能有抽象方法,没办法设置方法体,因此每个应用接口的类都要覆写抽象方法。而且,工厂设计模式下,每一个新的类都要在工厂类中新增方法。因此一定程度上还是不方便的。
- 但如果使用类的继承,虽然在客户端中要考虑new出来的类别,但是新增类会很简单。只要父类方法预设合适,子类中只需传递变量即可。
- 工厂类中的方法应为 static。这样不用new一个新对象即可以调用方法。
写的程序如下:
1. Sth 接口
interface Sth {
public abstract void canBeEaten();
public abstract void howToEat();
public abstract void delicious();
public abstract void getInfor();
}
2. Plant 接口
interface Plant extends Sth {
public abstract void color();
public abstract void smell();
}
2.1 Apple 类
public class Apple implements Plant {
public void canBeEaten() {System.out.print("苹果能吃。");}
public void howToEat() {System.out.print("苹果削皮吃。");}
public void delicious() {System.out.print("苹果可好吃。");}
public void color() {System.out.print("苹果有红有绿。");}
public void smell() {System.out.print("苹果很好闻。");}
public void getInfor() {
System.out.print("植物名称:苹果");
System.out.print("颜色:有红有绿");
System.out.print("气味:很好闻");
System.out.print("能怎好?:能吃、削皮吃、可好吃");
}
}
2.2 Grass 类
public class Grass implements Plant {
public void canBeEaten() {System.out.println("草不能吃。");}
public void howToEat() {System.out.println("草没法吃。");}
public void delicious() {System.out.println("草不好吃。");}
public void color() {System.out.println("草一般是绿的。");}
public void smell() {System.out.println("草闻起来很清新。");}
public void getInfor() {
System.out.println("植物名称:草");
System.out.println("颜色:一般是绿的");
System.out.println("气味:闻起来很清新");
System.out.println("能怎好?:不能吃、没法吃、不好吃");
}
}
3. Animal 类
public class Animal implements Sth {
private String name;
private String moveStyle;
private String foodStyle;
private boolean beEaten;
private String howEat;
private boolean tasteGood;
public Animal(){
}
public Animal(String name,String moveStyle,String foodStyle){
this.name = name;
this.moveStyle = moveStyle;
this.foodStyle = foodStyle;
}
public String getName() {return this.name;}
public void setName(String name) {this.name = name;}
public String getMoveStyle() {return this.moveStyle;}
public void setMoveStyle(String moveStyle) {this.moveStyle = moveStyle;}
public String getFoodStyle() {return this.foodStyle;}
public void setFoodStyle(String foodStyle) {this.foodStyle = foodStyle;}
public boolean getBeEaten() {return this.beEaten;}
public void setBeEaten(boolean beEaten) {this.beEaten = beEaten;}
public String getHowEat() {return this.howEat;}
public void setHowEat(String howEat) {this.howEat = howEat;}
public boolean getTasteGood() {return this.tasteGood;}
public void setTasteGood(boolean tasteGood) {this.tasteGood = tasteGood;}
public void move() {
System.out.println(this.name + "会" + this.moveStyle + "。");
}
public void food() {
System.out.println(this.name + "吃" + this.foodStyle + "。");
}
public void canBeEaten() {
if(this.beEaten){
System.out.println(this.name + "可以吃。");
}
else System.out.println(this.name + "不能吃。");
}
public void howToEat() {
if(this.beEaten){
System.out.println(this.name + howEat);
}
else System.out.println(this.name + "没法料理。");
}
public void delicious() {
if(this.beEaten && this.tasteGood){
System.out.println(this.name + "好吃!");
}
else System.out.println(this.name + "可难吃。");
}
public void getInfor() {
System.out.println("动物名称: " + this.name);
System.out.println("运动方式: " + this.moveStyle);
System.out.println("食物:" + this.foodStyle);
System.out.print("能怎好?:");
if(this.beEaten){
System.out.print("能吃、" + howEat + "、");
}
else System.out.print("不能吃、" + "没法料理、");
if(this.beEaten && this.tasteGood){
System.out.println("好吃");
}
else System.out.println("不好吃");
}
}
3.1 Bat 类
public class Bat extends Animal {
String name = "蝙蝠";
String moveStyle = "飞";
String foodStyle = "果子";
boolean beEaten = false;
String howEat = "";
boolean tasteGood = false;
public Bat(){
super();
super.setName(this.name);
super.setMoveStyle(this.moveStyle);
super.setFoodStyle(this.foodStyle);
super.setBeEaten(this.beEaten);
super.setHowEat(this.howEat);
super.setTasteGood(this.tasteGood);
}
}
3.2 Pig 类
public class Pig extends Animal {
private String name = "猪";
private String moveStyle = "跑";
private String foodStyle = "杂食";
private boolean beEaten = true;
private String howEat = "煮熟了吃";
private boolean tasteGood = true;
public Pig(){
super();
super.setName(this.name);
super.setMoveStyle(this.moveStyle);
super.setFoodStyle(this.foodStyle);
super.setBeEaten(this.beEaten);
super.setHowEat(this.howEat);
super.setTasteGood(this.tasteGood);
}
}
4. 工厂类
public class Factory {
// static 声明很重要!
public static Sth getInstance(String sthName){
if("bat".equals(sthName)){
return new Bat();
}
else if("pig".equals(sthName)){
return new Pig();
}
else if("apple".equals(sthName)){
return new Apple();
}
else if("grass".equals(sthName)){
return new Grass();
}
else return null;
}
public static Plant getInstance2(String sthName){
if("apple".equals(sthName)){
return new Apple();
}
else if("grass".equals(sthName)){
return new Grass();
}
else return null;
}
}
5. 测试
public class TestFactory {
public static void main(String[] args){
// 工厂设计模式——通过接口实例化对象
// 调用Sth接口中的抽象方法
Sth a = Factory.getInstance("pig");
a.delicious();
a.getInfor();
// 调用Plant接口中的抽象方法
Plant b = Factory.getInstance2("grass");
b.color();
b.getInfor();
// 通过子类实例化对象
Animal c = new Bat();
c.move(); // 调用Bat类中的抽象方法
c.food();
}
}
6. 结果
猪好吃!
动物名称: 猪
运动方式: 跑
食物:杂食
能怎好?:能吃、煮熟了吃、好吃
草一般是绿的。
植物名称:草
颜色:一般是绿的
气味:闻起来很清新
能怎好?:不能吃、没法吃、不好吃
蝙蝠会飞。
蝙蝠吃果子。