考题抄错会做也白搭——模板方法模式
大鸟说道:让小菜写一个抄题目的程序。
重复 = 易错 + 难改
- 甲的试卷
package template01;
public class TestPaperA {
public void testQuestion1(){
System.out.println("下列色彩由化学变化引起的是()\n A:节日的礼花\tB:夜晚的霓虹灯\tC:雨后的彩虹\tD:彩色的图画");
System.out.println("ans : A");
}
public void testQuestion2(){
System.out.println("下列物质种前者是混合物,后者是化合物的是()\nA:水 空气\tB:自来水 氧气\tC:矿泉水 冰水混合物\tD:高锰酸钾 双氧水");
System.out.println("ans: C");
}
public void testQuestion3(){
System.out.println("保持氧气化学性质的最小粒子是()\nA:氧原子\tB:氧气\tC:氧分子\tD:氧元素");
System.out.println("A");
}
}
- 乙的试卷
package template01;
public class TestPaperB {
public void testQuestion1(){
System.out.println("下列色彩由化学变化引起的是()\n A:节日的礼花\tB:夜晚的霓虹灯\tC:雨后的彩虹\tD:彩色的图画");
System.out.println("ans : C");
}
public void testQuestion2(){
System.out.println("下列物质种前者是混合物,后者是化合物的是()\nA:水 空气\tB:自来水 氧气\tC:矿泉水 冰水混合物\tD:高锰酸钾 双氧水");
System.out.println("ans: A");
}
public void testQuestion3(){
System.out.println("保持氧气化学性质的最小粒子是()\nA:氧原子\tB:氧气\tC:氧分子\tD:氧元素");
System.out.println("B");
}
}
- 客户端
package template01;
public class Client {
public static void main(String[] args) {
TestPaperA stu1 = new TestPaperA();
TestPaperB stu2 = new TestPaperB();
stu1.testQuestion1();
stu1.testQuestion2();
stu1.testQuestion3();
System.out.println("------------");
stu2.testQuestion1();
stu2.testQuestion2();
stu2.testQuestion3();
}
}
/* out:
下列色彩由化学变化引起的是()
A:节日的礼花 B:夜晚的霓虹灯 C:雨后的彩虹 D:彩色的图画
ans : A
下列物质种前者是混合物,后者是化合物的是()
A:水 空气 B:自来水 氧气 C:矿泉水 冰水混合物 D:高锰酸钾 双氧水
ans: C
保持氧气化学性质的最小粒子是()
A:氧原子 B:氧气 C:氧分子 D:氧元素
A
------------
下列色彩由化学变化引起的是()
A:节日的礼花 B:夜晚的霓虹灯 C:雨后的彩虹 D:彩色的图画
ans : C
下列物质种前者是混合物,后者是化合物的是()
A:水 空气 B:自来水 氧气 C:矿泉水 冰水混合物 D:高锰酸钾 双氧水
ans: A
保持氧气化学性质的最小粒子是()
A:氧原子 B:氧气 C:氧分子 D:氧元素
B
*/
甲乙两个类非常相似,只有答案不同,这么写容易出错,还不好维护。
提炼代码
- 试卷父类
package template02;
public class TestPaper {
public void testQuestion1(){
System.out.println("下列色彩由化学变化引起的是()\n A:节日的礼花\tB:夜晚的霓虹灯\tC:雨后的彩虹\tD:彩色的图画");
}
public void testQuestion2(){
System.out.println("下列物质种前者是混合物,后者是化合物的是()\nA:水 空气\tB:自来水 氧气\tC:矿泉水 冰水混合物\tD:高锰酸钾 双氧水");
}
public void testQuestion3(){
System.out.println("保持氧气化学性质的最小粒子是()\nA:氧原子\tB:氧气\tC:氧分子\tD:氧元素");
}
}
- 试卷子类
package template02;
public class TestPaperA extends TestPaper{
@Override
public void testQuestion1() {
super.testQuestion1();
System.out.println("ans:A");
}
@Override
public void testQuestion2() {
super.testQuestion2();
System.out.println("ans:B");
}
@Override
public void testQuestion3() {
super.testQuestion3();
System.out.println("ans:C");
}
}
public class TestPaperB extends TestPaper{
@Override
public void testQuestion1() {
super.testQuestion1();
System.out.println("ans:B");
}
@Override
public void testQuestion2() {
super.testQuestion2();
System.out.println("ans:C");
}
@Override
public void testQuestion3() {
super.testQuestion3();
System.out.println("ans:A");
}
}
但是子类中还有大量输出答案的语句 System.out.println("ans:C");
- 继承要有意义父类就得成为子类的模板,把所有重复的代码都写道父类,而不是让每个子类去重复。
模范方法实现
- 试卷父类
package template03;
public abstract class TestPaper {
public void testQuestion1(){
System.out.println("下列色彩由化学变化引起的是()\n A:节日的礼花\tB:夜晚的霓虹灯\tC:雨后的彩虹\tD:彩色的图画");
System.out.println("ans:" + ans01());
}
public void testQuestion2(){
System.out.println("下列物质种前者是混合物,后者是化合物的是()\nA:水 空气\tB:自来水 氧气\tC:矿泉水 冰水混合物\tD:高锰酸钾 双氧水");
System.out.println("ans:" + ans02());
}
public void testQuestion3(){
System.out.println("保持氧气化学性质的最小粒子是()\nA:氧原子\tB:氧气\tC:氧分子\tD:氧元素");
System.out.println("ans:" + ans03());
}
// 子类必须重写“答案”
public abstract String ans01();
public abstract String ans02();
public abstract String ans03();
}
- 试卷子类
package template03;
public class TestPaperA extends TestPaper {
@Override
public String ans01() {
return "A";
}
@Override
public String ans02() {
return "B";
}
@Override
public String ans03() {
return "C";
}
}
public class TestPaperB extends TestPaper {
@Override
public String ans01() {
return "B";
}
@Override
public String ans02() {
return "C";
}
@Override
public String ans03() {
return "C";
}
}
- 客户端
package template03;
public class Client {
public static void main(String[] args) {
// 多态
TestPaper stu1 = new TestPaperA();
TestPaper stu2 = new TestPaperB();
stu1.testQuestion1();
stu1.testQuestion2();
stu1.testQuestion3();
System.out.println("------------");
stu2.testQuestion1();
stu2.testQuestion2();
stu2.testQuestion3();
}
}
/* out:
下列色彩由化学变化引起的是()
A:节日的礼花 B:夜晚的霓虹灯 C:雨后的彩虹 D:彩色的图画
ans:A
下列物质种前者是混合物,后者是化合物的是()
A:水 空气 B:自来水 氧气 C:矿泉水 冰水混合物 D:高锰酸钾 双氧水
ans:B
保持氧气化学性质的最小粒子是()
A:氧原子 B:氧气 C:氧分子 D:氧元素
ans:C
------------
下列色彩由化学变化引起的是()
A:节日的礼花 B:夜晚的霓虹灯 C:雨后的彩虹 D:彩色的图画
ans:B
下列物质种前者是混合物,后者是化合物的是()
A:水 空气 B:自来水 氧气 C:矿泉水 冰水混合物 D:高锰酸钾 双氧水
ans:C
保持氧气化学性质的最小粒子是()
A:氧原子 B:氧气 C:氧分子 D:氧元素
ans:C
*/
模板方法模式
模板方法模式:定义一个操作中的算法骨架,将一些具体的步骤延迟到子类中去做。
模板方法使得子类可以不改变算法结构,即重新定义该算法中的某些步骤。
- 抽象类
package template04;
public abstract class AbstractClass {
// 算法骨架,某些算法的具体实现交给子类
public void template(){
primitiveOperation1();
primitiveOperation2();
primitiveOperation3();
}
public abstract void primitiveOperation1();
public abstract void primitiveOperation2();
public void primitiveOperation3(){
System.out.println("这里是公有的操作");
}
}
- 具体子类
package template04;
public class ConcreteClass1 extends AbstractClass{
@Override
public void primitiveOperation1() {
System.out.println("1 的具体操作");
}
@Override
public void primitiveOperation2() {
System.out.println("1 的具体操作");
}
}
public class ConcreteClass2 extends AbstractClass{
@Override
public void primitiveOperation1() {
System.out.println("2 的具体操作");
}
@Override
public void primitiveOperation2() {
System.out.println("2 的具体操作");
}
}
- 客户端
package template04;
public class Client {
public static void main(String[] args) {
AbstractClass c1 = new ConcreteClass1();
AbstractClass c2 = new ConcreteClass2();
c1.template();
c2.template();
}
}
/* out:
1 的具体操作
1 的具体操作
这里是公有的操作
2 的具体操作
2 的具体操作
这里是公有的操作
*/
模板方法模式特点
- 把不变的方法放到父类,去除子类重复的代码。
- 当不变的行为和可变的行为都出现在子类中时,不变的行为就会在子类中重复出现。我们需要将这些行为搬移到抽象父类,不变的行为就在父类写死,可变的行为交给子类来实现。