模板方法模式(多态的应用)

本文深入探讨了模板方法设计模式的原理与应用,通过实例展示了如何在固定算法骨架中允许子类灵活重定义某些步骤,同时保持算法结构不变。特别讨论了如何处理必须和可选步骤,以及使用抽象方法和钩子方法的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模板方法:在一个方法中定义一个算法的骨架,而将一些步骤延伸到子类中。
模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
首先设想以下情景。
我要在有一个特定背景的图上画一个对象,这个对象目前不知道具体是怎样的,它可以因人而异。我们用JAVA如何处理这种情形呢。
首先我们定义一个类把背景画好。

public class Picture {
	public static void picture() {
		System.out.println("画边框");
		System.out.println("画背景");
		
	    //画一个未知对象
		
		System.out.println("完成余下的工作");
	}
}

这个类只完成背景部分,对象部分未完成。
接下来我们可以在类外面画好特定的对象,然后当参数传进来。这种处理方法太过狭小并不能满足要求,要求是因人而异的对象,你总不能传n个参数进来吧。最好只传一个参数进来就能满足因人而异的要求。
我们可以将这个对象抽象化,我们只负责把画对象的事件定义好,至于怎么完成这件事就可以因人而异。用代码来说就是定义一个接口,接口里定义一个方法来完成这件事,至于怎么完成则由实现这个接口的类完成就可以了,利用多态将接口作为picture()的参数就可以完成因人而异的操作了。
完整代码:

public class Picture {
	public static void picture(Object object) {
		System.out.println("画边框");
		System.out.println("画背景");
		
	    //画一个未知对象
		object.paint();
		
		System.out.println("完成余下的工作");
	}
	public static void main(String[] args) {
		picture(new  man());
		picture(new Animal());
	}
}

class man implements Object{

	public void paint() {
		// TODO 自动生成的方法存根
		System.out.println("画一个人");
	}
	
}

class Animal implements Object{
	public void paint() {
		// TODO 自动生成的方法存根
		System.out.println("画一个动物");
	}
	
}
public interface Object {
       void paint();
}

除了向picture传参,我们还可以将picture中不确定的步骤用一个抽象方法代替。这样每个子类就可以根据不同的情况来实现这个方法。

public abstract class Picture2 {
	public void picture() {
		System.out.println("画边框");
		System.out.println("画背景");
		
	    //画一个未知对象
		paint();
		
		System.out.println("完成余下的工作");
	}
	abstract void paint();
}

public class Test {
    public static void main(String[] args) {
	    Picture2 man=new PMan();
	    Picture2 animal=new PAnimal();
	    man.picture();
	    animal.picture();
}
}
class PMan extends Picture2{
	void paint() {
		// TODO 自动生成的方法存根
		System.out.println("画一个人");
	}
	
}
class PAnimal extends Picture2{

	void paint() {
		// TODO 自动生成的方法存根
		System.out.println("画一个动物");
	}
	
}

这个代码跟上面的代码实质是一样,至于用参数还是抽象方法看个人和具体情况吧。
开篇的问题解决了,接下来我们对其进行延伸。首先注意到画一个对象到画里是必须的,所以我们对要用抽象方法来完成它,这样子类必须实现这个方法。
接下来我们对背景进行处理一下,为了使这幅画更加多样化,我们将背景拆分一下,一些景色变成可选的,因为个人审美观不同可以选择是否将这部分背景加上。
void must()方法表示必须的背景,void optional()方法表示可选背景。
我们再加一个方法 boolean choose()来实现可选。
这样子类就可以通过重写choose()方法来控制选与不选了。
注意这里choose()方法不能为抽象方法,如果为抽象方法每个子类就必须实现它,这样会使子类过于累赘。

public abstract class Picture2 {
	public void picture() {
		System.out.println("画边框");
		must();
		if (choose()) {
			optional();
		}
		
	    //画一个未知对象
		paint();
		
		System.out.println("完成余下的工作");
	}
	abstract void paint();
	private void must() {
		System.out.println("画必须背景");
	}
	
	private void optional() {
		System.out.println("画可选背景");
	}
	
	public boolean choose() {
		return true;
	}
}
public class Test {
    public static void main(String[] args) {
	    Picture2 man=new PMan();
	    Picture2 animal=new PAnimal();
	    man.picture();
	    animal.picture();
}
}
class PMan extends Picture2{
	boolean t=true;
	void paint() {
		// TODO 自动生成的方法存根
		System.out.println("画一个人");
	}
	
	public boolean choose() {
		return t;
	}
	
}
class PAnimal extends Picture2{
     boolean t=false;
    public boolean choose() {
		return t;
		
	}  
	void paint() {
		// TODO 自动生成的方法存根
		System.out.println("画一个动物");
	}
	
}

现在我们对上面两种情况做个总结。
明显的是两种情况都有固定的步骤。在固定步骤中间有一些不明确的步骤。而这不明确的步骤ye分两类。
第一类,这部分不明确的步骤是必须的,它不明确在它有多种选择。
第二类,这部分步骤是明确的,它不明确在于要不要实施。
针对这两类不明确情况,我们也有各自的对应方法。
第一类是必须的,所以我们用抽象方法来完成,因为子类必须实现抽象方法。
第二类是可选的,我们用普通方法来做出选择,选择与否通过子类是否重写它。子类重写的方法我们叫它做钩子。所以针对第二种情况我们可以创建钩子方法完成。
当然钩子方法不仅仅可以让子类是否实现步骤中的可选部分。它还可以让子类能够有机会对模板方法(即代码中的picture方法,picture方法作为画风景画这事件的模板)即将发生或已经发生的步骤做出反映。钩子方法也可以有能力为其抽象类作出决定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值