面向对象解决的一个小问题,觉得还好,就存一下

/**
*10、 一位老农带着猫、狗、鱼过河,河边有一条船,每次老农只能带一只动物过河。
*当老农不和猫狗鱼在一起时,狗会咬猫,猫会吃鱼,当老农和猫狗鱼在一起时,则不会发生这种问题。
*编程解决猫狗鱼过河问题。
*
*分析:
* 问题中的对象:猫、狗、鱼、老农、岸1(这岸)、岸2(对岸)
*
*
* 限制条件是:老农每次只能带一只动物过河
* 老农不在时,狗咬猫
* 老农不在时,猫吃鱼
* 目标是:将猫、狗、鱼从这岸运到对岸。
* 当农夫到达一个岸后,即为一个中间状态,则这个中间状态需要满足,岸1,岸2都是安全的
*
* 初始输入:是岸1中有3个对象,老农处在岸1
*
* 结果输出:将岸1中的对象移动到岸2中的具体步骤
*
* 岸1、岸2:可以添加不同类的对象,所以内部是一个集合,同时岸上是否有冲突,岸清楚,所以岸中有检测方法。
* 他们属于同一个类。对于具体要运送哪个对象才是合适的(即运送后岸是安全的),岸最清楚,所以要有
* 运送方法。
*
* 猫、狗、鱼:虽然是不同类,但是有共性,那就是他们可能有自己的天敌(也有可能没有),所以要有获取天敌的方法。
* 还有就是他们是否是安全的,所以有两个方法。
* 他们属于不同类,而检测是否安全的方法代码完全相同,所以定义一个抽象类来被他们继承。
*
* 老农:有两个方法,一个是自己过河,一个是运送动物过河。如何运送一个具体动物过河,以及运送该动物成功与否,
* 老农自己最清楚,老农是一个单独的类
*
* 审题结果:这个问题重在练习面向对象的思想和对象的设计,以及问题的分析能力,这个问题并不具备太强的
* 可扩展性,如果扩展大了,那么问题就改变了,不再是同类型的问题了。这是个A->B->C,有向图,且要首先
* 带走度为2的节点B,如果出现两个以上的度为2的节点,这个问题就无解了,如果出现一个度为3或者3以上的节点
* ,也是无解的。
*
*思路:
*
*1,定义 岸、猫、狗、鱼、老农 5个类
*2,老农运送 岸1中的一只动物到岸2,如果岸1处于和谐状态,则运送这只动物,否则换另一只动物。
*3,老农到达岸2后,检查岸2是否和谐,和谐,则自己离开,到2,否则运送一只动物离开,使其和谐,再到2
*4,全部运送完后,岸1空结束。
*
*(为使得代码尽量简洁,就不自定义hashCode,equals方法,程序中没有用到,但如果实际项目的话,需要进行
*覆盖。)
*/

package com.itheima;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//定义一个抽象类Animal,表示动物必须实现的方法,以及必须具备的功能
abstract class Animal 
{
	//每个动物都必须具备这项功能,即判断自己在给定的Bank下是否是安全的
	public boolean isSafe(Bank bank) {
		// TODO Auto-generated method stub
		return !(bank.containsClass(naturalEnemy())); //如果给定bank中天敌存在,则不安全,否则安全
	}

	//让子类去实现的方法,每个子类都要定义自己的天敌,并通过该方法返回
	public abstract String naturalEnemy();
}

//定义Bank类,表示“岸”这类事物
class Bank
{
	//定义Bank的名字,方便打印输出
	private String name = null;
	//定义容器,用来存储将要加进来的动物对象
	private Map<String, Object> map = new HashMap<String,Object>();
	
	//定义当前出现安全问题的动物
	private Animal currentProblem = null;
	
	//创建对象的时候,就指定岸对象的名字
	Bank(String name)
	{
		this.name = name;
	}
	
	@Override//覆盖toString方法
	public String toString()
	{
		return name;
	}
	//定义岸的添加动物对象的方法
	void add(Object obj)
	{
		map.put(obj.getClass().getName(), obj); //调用容器的相应添加方法
	}
	
	//定义岸的删除对象的方法,并返回删除的对象
	Object delete(Object obj)
	{
		return map.remove(obj.getClass().getName()); //调用容器的相应删除方法
	}
	//定义方法用来判断一种动物在该岸中是否存在
	boolean containsClass(String className)
	{
		return map.containsKey(className);
	}
	
	//打印Bank中的动物对象
	void printBank()
	{
		System.out.print(this+"  :  ");
		Set<Map.Entry<String,Object>> entrys = map.entrySet();//获取Map集合中的所有条目的Set集合
		
		//打印Bank中封装map容器中的内容,
		for(Map.Entry<String, Object> entry : entrys)
		{
			Animal obj = (Animal)entry.getValue();
			System.out.print(obj+"  "); //用空格分隔每个动物对象
		}
		System.out.println();
	}
	//判断岸的当前状态是否是安全的,即动物们是否是和谐相处的
	boolean isSafe()
	{
		boolean flag = true;
		
		Set<Map.Entry<String,Object>> entrys = map.entrySet();//获取Map集合中的所有条目的Set集合
		
		//循环判断每个动物是否是安全,如果每个动物都是安全的,那么岸就是安全的,否则岸就是不安全的
		for(Map.Entry<String, Object> entry : entrys)
		{
			String className = entry.getKey();
			Animal obj = (Animal)entry.getValue();
			
			if(!obj.isSafe(this)){ //判断动物在当前岸的状态下是否是安全的
				flag = false;
				currentProblem = obj; //如果不安全,则记录当前处于不安全状态的那个对象
				break;
			}
		}
		return flag; //返回结果
	}
	
	//定义方法供当前岸对象,指挥farmer,将自己的一个对象运送到对岸,也即bank
	boolean transport(Farmer farmer,Bank bank)
	{
		boolean flag = false;//初始设置为运送失败
		
		Map<String, Object> mapTemp = new HashMap<String,Object>(map);//拷贝副本,用来遍历
		
		//获取当前bank中目前有的对象
		Set<Map.Entry<String,Object>> entrys = mapTemp.entrySet();
		for(Map.Entry<String, Object> entry : entrys) //运送一个对象到bank,直到成功为止
		{	
			Animal obj = (Animal)entry.getValue();//取得一个具体的对象
		
			//指挥farmer将obj从当前岸(this)运送到彼岸(bank)
			if(farmer.transport(obj,this,bank))
			{
				flag = true;
				System.out.println("将 \""+obj+"\" 从 "+this+" 运送到 "+bank); //如果运送成功,则打印
				break;
			}	
		}
		
		return flag;
	}
	//定义方法,用来判断当前岸是否是空的状态,即当前岸中一个动物也没有
	boolean isEmpty()
	{
		return (map.size() == 0);
	}
}
//定义猫子类,继承父类Animal
class Cat extends Animal 
{
	//实现抽象方法,定义自己的天敌
	public String naturalEnemy() { 
		// TODO Auto-generated method stub
		return "com.itheima.Dog"; //将天敌的类型返回
	}
	
	@Override //覆盖toString方法,方便打印
	public String toString()
	{
		return "猫";
	}
}
//定义狗子类,继承父类Animal
class Dog extends Animal 
{
	//实现抽象方法,定义自己的天敌
	public String naturalEnemy() {
		// TODO Auto-generated method stub
		return "null"; //将天敌的类型返回,狗没有天敌,用"null"字符串表示没有天敌
	}
	@Override //覆盖toString方法,方便打印
	public String toString()
	{
		return "狗";
	}
}
//定义狗子类,继承父类Animal
class Fish extends Animal 
{
	//实现抽象方法,定义自己的天敌
	public String naturalEnemy() {
		// TODO Auto-generated method stub
		return "com.itheima.Cat"; //将天敌的类型返回
	}
	@Override //覆盖toString方法,方便打印
	public String toString()
	{
		return "鱼";
	}
}
//定义农夫类
class Farmer
{
	//定义属性animal,用来记录上一次运送的对象,防止死循环
	private Animal animal = null;
	
	//定义属性bank,用来表示农夫现在所处的位置是哪个岸
	private Bank bank = null;
	
	//初始化时,指定farmer位于那个岸,即哪个bank
	Farmer(Bank bank)
	{
		this.bank = bank;
	}
	
	//农夫只将自己运送到指定的岸bank
	boolean transport(Bank bank)
	{
		this.bank = bank;
		return true;
	}
	
	//farmer将指定对象obj,从bank1运送到bank2
	boolean transport(Object obj,Bank bank1,Bank bank2)
	{
		this.bank = bank2; //farmer即将划船到bank2
		
		//obj刚刚才运过,刚从bank2运送到bank1,所以不能再从bank1运送到bank2了
		if(animal == obj)
			return false; //直接返回运送失败
		
		//开始运送obj,现将其从bank1中删除
		animal = (Animal)bank1.delete(obj);
		
		//看看bank1是否是安全的
		if(bank1.isSafe())
		{
			bank2.add(obj); //bank1安全,将obj运送到bank2,即添加进bank2
			return true;
		}
		else //bank1不是安全的,运送失败
		{
			bank1.add(obj); //运送失败,将obj添加回bank1
			
			return false; //返回运送失败
		}
		
	}
	@Override //覆盖toString方法,方便打印
	public String toString()
	{
		return "农夫";
	}
	
	//打印农夫现在位于哪个岸
	void printBank()
	{
		System.out.println(this+"  位于   "+bank);
	}
}

//测试类
public class Test10 {
	
	//用于打印问题的初始情况
	public static void initSituation(Farmer farmer ,Bank bank1,Bank bank2)
	{
		System.out.println("初始情况:");
		
		bank1.printBank();
		bank2.printBank();
		farmer.printBank();
		System.out.println("-------------------------------------");
		
	}
	//用于打印问题的最终情况
	public static void endSituation(Farmer farmer ,Bank bank1,Bank bank2)
	{
		System.out.println("-------------------------------------");
		System.out.println("最终情况:");
		
		bank1.printBank();
		bank2.printBank();
		farmer.printBank();
	}
	//main函数
	public static void main(String[] args) {
		//创建bank1,bank2
		Bank bank1 = new Bank("岸A");
		Bank bank2 = new Bank("岸B");
		//将猫、狗、鱼添加到bank1中
		bank1.add(new Dog());
		bank1.add(new Cat());
		bank1.add(new Fish());
		//创建农夫对象farmer
		Farmer farmer = new Farmer(bank1);
		
		//打印问题的初始情况
		initSituation(farmer, bank1, bank2);
		
		//一直运送直到bank1岸为空
		while(!bank1.isEmpty())
		{
			//bank1不为空,则从bank1运送一个对象到bank2
			if(bank1.transport(farmer, bank2))
			{
				//运送完一次,立即判断bank1是否为空,如果为空,则完成目标,跳出循环,结束
				if(bank1.isEmpty())
					break;
				
				//如果bank1运送成功,则农夫从bank2返回到bank1,并检查bank2当前是否安全,由此决定以何种
				//方式返回到bank1,是只运送自己,还是再从bank2中带走一个对象到bank1
				if(bank2.isSafe())
				{
					System.out.println("\""+farmer+"\""+" 自己一个人从  "+bank2+"  划船到  "+bank1); //如果运送成功,则打印
					farmer.transport(bank1);//bank2安全,只运送自己到bank1
				}
				else
				{
					bank2.transport(farmer,bank1);//bank2不安全,需要带走bank2中的一个对象到bank1
				}
			}
			else
			{
				System.out.println("对于这个问题,暂时无解");//针对于这个具体的问题,出现这种情况意味着无解
			}
		}
		
		//打印问题的最终情况
		endSituation(farmer, bank1, bank2);
	}

}

  

posted @ 2015-04-18 19:04  蓝色T-shirt  阅读(246)  评论(0编辑  收藏  举报