吉林大学设计模式第四次作业(上)

找到这里的多半是我的学弟学妹了,怎么说呢,希望能帮到你们吧,也更希望我留在这里的思路和代码是你们的下限,设计模式真的很精妙,祝你们有所增益。


题目一

开发一个消防应急响应系统,火灾探测器(FireDetector)发现火灾异常后将自动传递信号给各种响应设备,例如警示灯(WarningLight)将闪烁(flicker())、报警器(Alarm)将发出警报(alarm())、安全逃生门(SecurityDoor)将自动开启(open())、隔离门(InsulatedDoor)将自动关闭(close())等,每一种响应设备的行为由专门的程序来控制。请写出你所选择的设计模式,画出类图,并给出核心代码。

由题意得这道题显然要使用观察者模式——当一个对象被修改时,则会自动通知依赖它的对象。

而观察者模式使用三个类:

  • Subject:抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
    • 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  • Observer:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
    - 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
  • Client

在这里插入图片描述
结合在这道题里:

  • Subject:抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法notifyObserver()。
    • 具体目标类(Concrete Subject):它实现抽象目标中的通知方法notifyObserver(),当发现火灾异常后将自动传递信号给各种响应设备(具体观察者),通知所有注册过的观察者对象。
      - 火灾探测器(FireDetector)
  • Observer:它是一个抽象类或接口,它包含了一个更新自己的抽象方法response(),当接到具体主题的更改通知时被调用。
    - 具体观察者(Concrete Observer)角色:
    - 警示灯(WarningLight):response(){//闪烁(flicker())}
    - 报警器(Alarm):response(){//发出警报(alarm())}
    - 安全逃生门(SecurityDoor):response(){//将自动开启(open())}
    - 隔离门(InsulatedDoor):response(){//将自动关闭(close())}
  • Client

代码:

import java.util.*;
public class Client {
    public static void main(String[] args) {
    
        //目标火灾探测器
        Subject subject = new FireDetector();
        //观察者
        Observer obs1 = new WarningLight();
        Observer obs2 = new Alarm();
        Observer obs3 = new SecurityDoor();
        Observer obs4 = new InsulatedDoor();
        
        subject.add(obs1);
        subject.add(obs2);
        subject.add(obs3);
        subject.add(obs4);
        subject.notifyObserver();
    }
}
//抽象目标
abstract class Subject {
    protected List<Observer> observers = new ArrayList<Observer>();
    //增加观察者方法
    public void add(Observer observer) {
        observers.add(observer);
    }
    //删除观察者方法
    public void remove(Observer observer) {
        observers.remove(observer);
    }
    public abstract void notifyObserver(); //通知观察者方法
}
//具体目标
class FireDetector extends Subject {
    public void notifyObserver() {
        System.out.println("注意注意!发生火灾异常!");
        System.out.println("--------------");
        for (Object obs : observers) {
            ((Observer) obs).response();
        }
    }
}
//抽象观察者
interface Observer {
    void response(); //反应
}
//具体观察者1
class WarningLight implements Observer {
    public void response() {
        System.out.println("警示灯开始闪烁!");
    }
}
//具体观察者1
class Alarm implements Observer {
    public void response() {
        System.out.println("报警器发出警报!");
    }
}

//具体观察者1
class SecurityDoor implements Observer {
    public void response() {
        System.out.println("安全逃生们已自动开启!");
    }
}

//具体观察者1
class InsulatedDoor implements Observer {
    public void response() {
        System.out.println("隔离门已自动关闭!");
    }
}

输出:
在这里插入图片描述


题目二

**某学校的差旅费报销制度规定,要根据不同的报销金额,由不同的领导审批,1万元以下科长审批,1万元至5万元之间处长审批,5万元至10万元之间副校长审批,10万元以上校长审批。最常用的编程思想是采用条件语句进行判断,但是随着差旅费报销制度的逐渐完善,可能需要判断的条件会越来越多,可能处理的逻辑也更加复杂,代码将变得难以维护。请选择恰当的设计模式解决该问题,画出类图,写出关键代码。
**

这道题是典型的责任链模式的应用。核心就是审批旅费报销这件事,经由不同的领导才能审批不同的额度。倘若员工必须根据费用的多少去找对应的领导那意味着他必须记住每个领导的信息,这是不现实的,实际运用中我们更希望我就找直系领导,他要是解决不了他就把这件事往上递交,而我本身只用跟一个领导交互。

职责链模式主要包含以下角色。

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。这道题里对应有四个具体处理者。
    - Chief:科长,处理1万元以下审批
    - Director:处长,处理1-5万元
    - VicePrincipal:副校长,处理5-10万元审批
    - Principal:校长,处理10万元以上审批
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

unl类图:

请添加图片描述

import java.io.IOException;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws IOException {
        //组装责任链
        Handler handler1 = new Chief();
        Handler handler2 = new Director();
        Handler handler3 = new VicePrincipal();
        Handler handler4 = new Principal();
        handler1.setNext(handler2);
        handler2.setNext(handler3);
        handler3.setNext(handler4);

        //提交请求
    
        System.out.println("请选择要想申请的审批额度:\n——①1万元以下;\n——②1万元-5万元;\n——③5万元-10万元;\n——④10万元以上。");
        int in = System.in.read();  
        handler1.handleRequest(in-48);
    }
}
//抽象处理者角色
abstract class Handler {
    private Handler next;
    public void setNext(Handler next) {
        this.next = next;
    }
    public Handler getNext() {
        return next;
    }
    //处理请求的方法
    public abstract void handleRequest(int request);
}
//具体处理者角色1
class  Chief extends Handler {
    public void handleRequest(int request) {
        if (request == 1) {
            System.out.println("科长正在处理该请求!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("没有人处理该请求!");
            }
        }
    }
}
//具体处理者角色2
class Director extends Handler {
    public void handleRequest(int request) {
        if (request == 2) {
            System.out.println("处长处理该请求!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("没有人处理该请求!");
            }
        }
    }
}

//具体处理者角色3
class VicePrincipal extends Handler {
    public void handleRequest(int request) {
        if (request == 3) {
            System.out.println("副校长正在处理该请求!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("没有人处理该请求!");
            }
        }
    }
}

//具体处理者角色2
class Principal extends Handler {
    public void handleRequest(int request) {
        if (request == 4) {
            System.out.println("校长正在处理该请求!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("没有人处理该请求!");
            }
        }
    }
}

输出:
请添加图片描述

题目三

小王准备使用面向对象的方法设计一个快餐店的简单游戏,游戏中有顾客、服务员、菜品和厨师。每个顾客都有一个服务员帮助点菜,并且可以点多个菜;每道菜都由指定厨师制作,不同的菜可能由不同的厨师制作;顾客跟服务员点完菜后,服务员通知后厨做菜。请你针对上面的描述,帮助小王选择合适的设计模式进行设计。
1)简要说明你的设计思路和选择的模式。

老师给的标准答案:命令模式。……呜呜呜呜设计模式好难,稍微场景设置花一点完全设计不对呜呜呜呜

首先分析这道题,实质就是:服务员帮助顾客点菜,通知后厨做菜,不同菜可能由不同的厨师制作。
因此,其实可以分析出大概了,服务员特别像一个接口,与客户交互,然后将结果通知厨师,厨师根据菜品的不同分化给具体的人做。所以这道题我选择采用外观模式+职责链模式。

  • 外观模式:客户-服务员-得到点菜菜品
  • 职责链模式:菜品-具体厨师负责,相当于让相应的菜品自动匹配能做的厨师(不过下面解决中使用了哈希表就不用详写职责链了)

2)给出你设计的UML类图和实现代码。

请添加图片描述

import java.util.HashMap;


class Dish {
	public String name;		//菜肴的名称
	public Dish(String n) {	//初始化函数
		name=n;
	}
	public void cooked(){
	   System.out.println(name + "已做好!");
	}
}

class Chief {
	public String name;			//厨师的名称
	public List<dish>d = new ArrayLsit(); //每个厨师会做的菜
	public Chief(String n) {
		name  = n;
	}
	public void cook(String dishName) {
		System.out.println("正在做菜");
		d.get(dishNmae).cooked;
	}
}


class Waiter {
	private HashMap<String,Chief>map;			// Hash表用来保存每个厨师对应一个菜
	public Waiter() {
		map = new HashMap<String, Chief>();
		Chief chief_example = new Chief("example_chief");
		map.put("example", chief_example);
	}										//服务员掏出了菜单
	public void getOrder(Dish dish) {		// 服务员接收到指定的菜单找厨师做菜
		System.out.println(map.get(dish.name).name);//获取当前厨师名字
		map.get(dish.name).cook(dish.name); //调用该厨师做这道菜的方法
	}
}

class Customer {
	private Waiter waiter;
	//每个顾客都有一个服务员帮忙点菜
	public Customer() {
		waiter = new Waiter();
	}
	public void Order(Dish dish) {
		//点菜dish
		waiter.getOrder(dish);
	}
}

public class Client {
 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Customer customer = new Customer();
		Dish dish = new Dish("example");
		customer.Order(dish);
	}
 

题目四

小明为某银行开发一个报警系统,该系统功能描述如下,请你帮助小明完成设计,给出设计模式的名称,画出类图,写出关键代码。
在这里插入图片描述

老师给的标准答案是:状态模式。emmmm这道题输的心服口服好吧,做的时候压根没学状态模式hhhh

我认为应该使用观察者模式
请添加图片描述

import java.util.*;
public class Client {
    public static void main(String[] args) {
    
    	AlarmSystem subject = new Treasury();
        //观察者
        Observer obs1 = new Alarm();
        Observer obs2 = new Telephone();
        
        subject.add(obs1);
        subject.add(obs2);
   
        subject.notifyObserver();
    }
}
//抽象目标
abstract class AlarmSystem {
    protected List<Observer> observers = new ArrayList<Observer>();
    //增加观察者方法
    public void add(Observer observer) {
        observers.add(observer);
    }
    //删除观察者方法
    public void remove(Observer observer) {
        observers.remove(observer);
    }
    public abstract void notifyObserver(); //通知观察者方法
}
//具体目标
class Treasury extends AlarmSystem {
    public void notifyObserver() {
        System.out.println("金库启动:");
        System.out.println("--------------");
        if(时间位于900~1659) {
            for (Object obs : observers) {
            ((Observer) obs).responseDay();
             }
        }else(时间位于000~8591700~2359) 
        {
        	for (Object obs : observers) {
            ((Observer) obs).responseNight();
        }
        	
        }
    }
}
//抽象观察者
interface Observer {
    void responseDay(); //白天反应
    void responseNight();//夜晚反应
}

class Alarm implements Observer {
    public void responseDay() {
        System.out.println("警铃正在调用。");
        System.out.println("向警报中心发送紧急事态通知!");
    }
    public void responseNight() {
        System.out.println("警铃正在调用。");
        System.out.println("向警报中心发送紧急事态通知!");
    }
}

class Telephone implements Observer {
    public void responseDay() {
    	System.out.println("电话正在调用。");
        System.out.println("正在呼叫警报中心");
    }
    public void responseNight() {
    	System.out.println("夜间留言电话正在调用。");
        System.out.println("正在呼叫警报中心的留言电话");
    }
}

题目五

** 小明正在开发一个病房呼叫应答仿真系统。系统中每个病房配备一个呼叫按钮和一个呼叫显示应答器,疗区大厅配备一个显示应答器和一个语音播报器。假设,按下001号病房的呼叫按钮后,那么,所有的呼叫显示应答器都会显示发出呼叫的病房号001,大厅同时语音播报该病房号001。当医护人员按下任意一处的呼叫显示应答器的应答按钮后,所有呼叫显示应答器停止显示该房间号,大厅也停止语音播报。请用恰当的设计模式实现该系统,画出类图,给出核心代码。**

已经麻木了,老师给的标准答案是:中介者模式。想一想也符合,原先的场景里病人、呼叫应答器、显示应答器、语音播报器、医护人员相互杂糅,有个中介者类把多对多关系变成一对一好像蛮不错的。但其实中介者模式和观察者模式都是行为型模式,核心是相似的,所以自己开始弄错了。

我觉得要使用观察者模式和单例模式

类图:
请添加图片描述

import java.util.ArrayList;
import java.util.List;
class Asking{
	public String name;
	public Asking(String name) {
		this.name=name;
	}
	public void show() {
		System.out.println(name);
	}
	public void back() {
		//撤回显示
	}
}

class Button{
	public String name;
	Asking a = null;
	public static List<Asking> ask = new ArrayList();
	public Button(String name) {
		this.name=name;
		a = new Asking(name);
		ask.add(a);
	}
	public void getButton() {
		for(int i =0;i<ask.size();i++) {
			a = ask.get(i);
			a.show();
		}
	}
}

class Doctor extends Button{
  
	public Doctor(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}

	public void getButton() {
		for(int i =0;i<ask.size();i++) {
			a = ask.get(i);
			a.back();
		}
	}
}
作业04 行为型+其它(以step0_src中代码为基础) 1. 将玩家改为只有两个Player,一个HumanPlayer,一个AutoPlayer。初始时,各玩家都站在map中的第一个Block上,初始的移动方向任意。每轮次HumanPlayer玩家前进3格,AutoPlayer前进2格。前进方向任意,但若前方有格子(前进、左转、右转),必定前进,而不能往回走。HumanPlayer所在的格子用[X]表示,AutoPlayer的格子用(X)表示。实现代码。 2. 在Players的代码中,通过getFirst和getLast取得两个玩家,但这两个成员函数与Player用deque表示紧密相关,且只能取得前后两个Player。考虑到玩家数量可多个,玩家集合的数据结构可多样,用迭代器模式重新实现遍历所有玩家的功能,要求分别实现C++风格的外部迭代器和Java风格的外部迭代器。迭代器接口如下: class CppIterator { public: CppIterator( ) {} virtual ~CppIterator( ) {} virtual void first() = 0; virtual void next() = 0; virtual bool isLast() const = 0; virtual void * current() = 0; virtual int count() const=0; }; class JavaIterator { public: JavaIterator() {} virtual ~JavaIterator() {} virtual void* next() = 0; virtual bool hasNext() const = 0; virtual int count() const=0; }; 3. 若玩家前进时,各玩家的前进策略多种多样,如一种策略是各可能方向是等概率的(例如1中的代码),另一种策略是各方向有不同几率:inDir未确定时,向各方向前进的概率相等;inDir确定时,各方向的概率不一定相同。具体可见下表。而且以后可能会添加新的前进策略,如具有AI的策略等;玩家还可能需要动态改变前进策略。使用策略模式实现。 inDir==NONE时 inDir!=NONE时 连通四个方向 各方向各25% 直行50%,左转25%,右转25% 连通往三方向 各方向各33% 可直行时,直行60%,左转(或右转)40%; 不可直行时,左转和右转各50% 连通两个方向 各方向各50% 与inDir不同的方向为100% 连通一个方向 各方向各100% 100%地转向往回走 4. 为提高趣味性,增加了卡片子系统和魔法子系统, Player可以使用卡片、魔法等,作用于各玩家或系统中的其它对象上。部分类图如下: 这里使用RobCard会抢走指定玩家的一半金钱;使用MeanCard会平均所有玩家的金钱;使用ReturnSpell会使指定玩家直接返回到开始的Block,inDir不定。 1) 修改PlayMenu为: PlayMenu 1. Go… 2. ApplyRobCard 3. ApplyMeanCard 4. ApplyReturnSpell 5. Load 6. Save 7. Back To MainMenu Your selected: 并给Player类添加行为ApplyRobCard(Player * target);、ApplyMeanCard();和ApplyReturnSpell(Player * target),然后实现。 2) 以后肯定要添加其它Card和Spell,还有可能增加道具子系统等。由于Player已有子类AutoPlayer和HumanPlayer,而且未来扩展Card、Spell和道具等时,作用目标target有多种可能,如Player、Block、Player集合,甚至Card类等,所以希望在未来扩展时,避免通过继承Player类或其子类进行扩展。使用命令模式实现此目地。 5. 若需要增加FlyCard和FreezeSpell。其作用是:当应用FlyCard到某个Player上时,该player将每轮次前进6格,并持续2个轮次;当施加FreezeSpell到某个Player上时,该player将每轮次只前进1格,并持续3个轮次。 考虑到以后还会添加其它类似功能的Card和Spell,但不希望直接从Player类派生子类进行扩展。使用状态模式实现此目的。 6. 若还需要增加HurtSpell,该Spell会导致被作用的Player,每轮次减少Money的数量5,并持续2
作业03 结构型模式 1. 现Mouse类的定义如下: class Mouse { public: void Walk( int steps ) { cout<<"Implement for Walk() with Verson 1."} void AddMoney(int m) { cout<<"Implement for AddMoney() with Verson 1."} private: int posX; int posY; }; 若已知:在后续的版本中 a)可能会增加Mouse类的其他行为,如增加Drive(int steps)和Fly(int steps); b)可能需要改变Walk(int steps)的具体实现细节; c)可能会增加其它数据成员,如将2D位置信息改为3D位置信息等。 d)希望在新版本中,尽可能地通过扩展老版本,适应新需求。 使用桥接模式重新设计Mouse类及相关类,并简要说明如何适应变化a-d。 2. 设计并实现一个foo.dll,其中含有类如下: a) 若foo.dll直接导出了类Foo、类FooA、类FooB,使用类适配器和对象适配器,实现 class User { public: int myProcess( ) { /*适配Foo.process(); */ } }; b) 若foo.dll没有导出类Foo、类FooA、类FooB,但导出函数shared_ptr createFooA();和shared_ptr createFooB();,使用对象适配器使得User可以适配任意指定的Foo类族的子类对象的process。 3. 针对给出的场景、描述说出最适当的模式名字,并用文字或示例代码给出简要的使用说明或解释。 1) 开发一个用于数值计算的大型程序库,它的功能是强大的,但需要使用者具备较高的数学专业知识。为方便“菜鸟”级用户的使用,需要提供一个简化版的,但同时又不希望影响专业人员的使用。使用哪种设计模式较好?如何设计? 2) 在2D游戏的开发中,需要绘制地图,地图是由大量的“一样的图块”拼接而成,而“图块”的种类有限,目前有草地、海洋、沙漠、山地等,未来肯定要增加种类,但不会太多太频繁。采用何种模式组织“图块”类比较好?如何设计? 3) 在开发一个办公自动化系统时,项目组在ElectricSignature类集中实现了电子签名的功能。但在使用中发现该类不能完全满足用户需求,由于财力和人员的限制,决定直接购买第三方电子签名软件,其中的FZ_ESignet类功能与ElectricSignature的功能一样,但是两个类中的函数名都是不一样的,而且购买的只是二进制代码,没有源代码。现希望使用第三方软件的功能,但又不希望修改ElectricSignature的接口。使用哪种设计模式改进较好?如何改进? 4) 某书店需要开发一套图书购销存软件。在设计图书类时发现:图书有单行本和成套的,又细分成教辅材料、科学知识、文学著作等。设计时,希望能够以一致的方式访问各种图书,不论是单本的、成套的、IT类的或古典名著。使用哪种设计模式较好?如
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值