概述
找到这里的多半是我的学弟学妹了,怎么说呢,希望能帮到你们吧,也更希望我留在这里的思路和代码是你们的下限,设计模式真的很精妙,祝你们有所增益。
题目六
开发一个计算机操作系统的线程调度程序,要求实现时间片调度和抢占调度这2种调度算法,并且支持Windows、Unix和Linux这3个操作系统,考虑到调度算法的实现与具体操作系统紧密相关,并且将来有可能会增加新的调度算法和支持新的操作系统,请选择恰当的设计模式解决该问题,画出类图,写出关键代码。
这道题我们老师给的标准答案是桥接模式,我后来回看觉得确实桥接模式更合适,因为题干上将该程序进行了两个维度上的划分——算法和操作系统,所以桥接模式对这两个紧密相关的属性进行抽象实现更加适合。hhh抽象工厂模式虽然具有一般性,但分析解决问题的时候还是不能一味将它当作万金油。
这道题我觉得也可以使用抽象工厂模式,是第五题的升级版,抽象一下核心就是:xxx算法的实现依赖于yyy操作系统
那么在这里xxx算法搞一个工厂统一接口,yyy操作系统搞一个工厂统一接口,对于客户端而言那就是在yyy操作系统上实现xxx算法,思路成立!
所以UML类图为:
核心代码:
public class AlgorithmFactory {
public void AlgorithmShow() {
//增加一种操作系统下算法的实现方式
}
}
class PreemptiveScheduling extends AlgorithmFactory{
public void AlgorithmShow() {
System.out.println("此为抢占调度算法实现");
}
}
class TimeSliceAgorithm extends AlgorithmFactory{
public void AlgorithmShow(){
System.out.println("此为时间片调度算法实现");
}
}
import java.util.ArrayList;
import java.util.List;
public class OS{
private String OSname1;
private List<AlgorithmFactory>list=new ArrayList();
public OS(String name) {
this.OSname1=name;
}
public void AddAlgorithm(AlgorithmFactory af) {
list.add(af);
}
public void AlgorithmRun1() {
System.out.println(OSname1);
for(int i =0;i<list.size();i++) {
AlgorithmFactory af = list.get(i);
af.AlgorithmShow();
}
}
}
class WindowsOS extends OS {
public WindowsOS(String name) {
super(name);
System.out.println(name+"准备就绪!");
// TODO Auto-generated constructor stub
}
}
class UnixOS extends OS{
public UnixOS(String name) {
super(name);
System.out.println(name+"准备就绪!");
// TODO Auto-generated constructor stub
}
}
class LinuxOS extends OS{
public LinuxOS(String name) {
super(name);
// TODO Auto-generated constructor stub
System.out.println(name+"准备就绪!");
}
}
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
OS os0 = new WindowsOS("Windows");
OS os1 = new UnixOS("Unix");
OS os2 = new LinuxOS("Linux");
AlgorithmFactory af0 = new PreemptiveScheduling();
AlgorithmFactory af1 = new TimeSliceAgorithm();
os0.AddAlgorithm(af0);
os0.AddAlgorithm(af1);
os0.AlgorithmRun1();
}
}
输出:
题目七
某饮料店卖饮料时,可以根据顾客的要求在饮料中加入各种配料,饮料店会根据顾客所选的饮料种类和所加入的配料来计算价格。饮料店所供应的部分饮料及配料的种类和价格如下表所示。请你选择恰当的设计模式,为该饮料店开发一个计算饮料价格的程序,要求给出设计思路,画出类图,并写出关键代码
想看装饰模式可以先看题目九,那道题我写的很详细(主要当时顺着写作业写烦了就倒着做)
我觉得应该使用装饰模式。分析原题目,这实际上就是一种加工,每次加工得到一个新对象。并且加工的动作之间可以动态转换,多次装饰。
public abstract class Beverage {
String name;
private int price;
public Beverage (String name,int price){
this.name =name;
this.price=price;
}
public abstract int getPrice(); //实现价格计算的业务
}
//实际的被装饰对象
class MilkTea extends Beverage {
public MilkTea(String name, int price) {
super(name, price);
// TODO Auto-generated constructor stub
}
@Override
public int getPrice() {
return 8; // 描述价格
}
}
class MilkShake extends Beverage {
public MilkShake(String name, int price) {
super(name, price);
// TODO Auto-generated constructor stub
}
@Override
public int getPrice() { // 价格
return 9;
}
}
class Coffee extends Beverage {
public Coffee(String name, int price) {
super(name, price);
// TODO Auto-generated constructor stub
}
@Override
public int getPrice() { // 价格
return 10;
}
}
public abstract class Condiment {
protected Beverage beverage = null;
private String name;
private int price;
// 构造方法
public Condiment(Beverage beverage,String name,int price) {
this.beverage =beverage;
this.name= name;
this.price = price;
}
public abstract int getDescription(); //抽象装饰的内容
}
class Strawberry extends Condiment {
public Strawberry(Beverage beverage, String name, int price) {
super(beverage, name, price);
// TODO Auto-generated constructor stub
}
public int getDescription() {
System.out.print("加了 草莓、" + beverage.name+"的价格:");
return 2 + beverage.getPrice(); // 草莓价格加上具体饮品的价格
}
}
class Pudding extends Condiment {
public Pudding(Beverage beverage, String name, int price) {
super(beverage, name, price);
// TODO Auto-generated constructor stub
}
public int getDescription() {
System.out.print("加了 布丁、" + beverage.name+"的价格:");
return 3 + beverage.getPrice(); // 布丁价格加上具体饮品的价格
}
}
class Cheese extends Condiment {
public Cheese(Beverage beverage, String name, int price) {
super(beverage, name, price);
// TODO Auto-generated constructor stub
}
public int getDescription() {
System.out.print("加了 芝士雪酪、" + beverage.name+"的价格:");
return 4 + beverage.getPrice(); // 布丁价格加上具体饮品的价格
}
}
public class Client {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Beverage b1,b2,b3;//抽象构件独
Condiment c1,c2,c3;
b1=new MilkTea("奶茶",8);//子类实例化对象
c1=new Strawberry(b1,"草莓",2); //添加装饰类购件
System.out.println(c1.getDescription()+"元");
b2=new MilkShake("奶昔",9);
c2=new Pudding(b2,"布丁",3);
System.out.println(c2.getDescription()+"元");
b3=new Coffee("咖啡",10);
c3=new Cheese(b3,"芝士雪酪",4);//添加构件橘子汁
System.out.println(c3.getDescription()+"元");
}
}
题目八
小王为某五星级酒店开发点餐系统。该酒店为满足客户需要,会在不同的时段提供多种不同的餐饮,其菜单的结构图如图所示。
请你采用面向对象方法通过恰当的设计模式帮助小王对上述菜单进行设计。
首先这是一个树形结构,我们可以发现不同的子菜单有大致相同的功能,只是细节划分不同,而这跟我们设计模式中的**“组合模式”**理念一致——它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式。
而该模式包含的主要角色是:
- 抽象构件角色:是为树叶构件声明公共接口,并实现它们的默认行为(在题中所设场景对应的我设计了一个抽象构件MyElement,用于为菜单和菜式构建对象提供共同的接口。在该抽象构件中定义了访问及管理它的子构件的方法,比如增加菜单、删除菜单、获取菜品名等。)
- 树叶构件:用于继承或实现抽象构件(具体菜品,代码表示为DishStyle类,是MyElement的实现)
- 树枝构件角色:也叫中间构件,是组合中的衔接,主要作用是存储和管理子部件(也就是子菜单,代码表示为Menu类,该构件设计为一个容器构件,实现了MyElement的具体行为,包括那些访问以及管理菜单和菜式的方法)
代码:
//MyElement.java
public abstract class MyElement {
public abstract void add(MyElement myElement);
public abstract void remove(MyElement myElement);
public abstract MyElement get(int i);
public abstract void method();
}
//Menu.java
import java.util.ArrayList;
import java.util.List;
public class Menu extends MyElement{
private List<MyElement> list;
private String name;
public Menu() {};
public Menu(String name) {
this.name=name;
list=new ArrayList<MyElement>();
}
public void add(MyElement myElement) {
list.add(myElement);
}
public void remove(MyElement myElement) {
list.remove(myElement);
}
public MyElement get(int i) {
return null;
}
public void method() {
System.out.println("调用菜单方法!");
int i=0;
for(MyElement my:list) {
System.out.print(i+":");
i++;
my.method();
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//DishStytle.java
public class DishStyle extends MyElement{
public DishStyle() {};
public void add(MyElement myElement) {
try {
new Exception();
}catch(Exception e) {
System.out.println("禁止使用!");
}
}
public void remove(MyElement myElement) {
try {
new Exception();
}catch(Exception e) {
System.out.println("禁止使用!");
}
}
public MyElement get(int i) {
try {
new Exception();
}catch(Exception e) {
System.out.println("禁止使用!");
}
return null;
}
public void method() {
System.out.println("此为菜式!");
}
}
//Client.java
public class Client {
public static void main(String args[]) {
MyElement pancakeHouse=new Menu("煎饼屋菜单");
MyElement restaurant=new Menu("餐厅菜单");
MyElement coffee=new Menu("咖啡厅菜单");
MyElement dessert=new Menu("甜点菜单");
MyElement stytle1=new DishStyle();
MyElement stytle2=new DishStyle();
MyElement stytlem=new DishStyle();
MyElement stytlen=new DishStyle();
MyElement stytler=new DishStyle();
MyElement stytlet=new DishStyle();
MyElement stytleu=new DishStyle();
MyElement stytley=new DishStyle();
pancakeHouse.add(stytle1);
pancakeHouse.add(stytle2);
pancakeHouse.add(stytlem);
restaurant.add(stytlen);
restaurant.add(dessert);
dessert.add(stytleu);
dessert.add(stytley);
coffee.add(stytler);
coffee.add(stytlet);
System.out.println("********煎饼屋菜单演示********");
pancakeHouse.method();
System.out.println("********餐厅菜单演示********");
restaurant.method();
System.out.println("********咖啡厅菜单演示********");
coffee.method();
}
}
输出(前面序号表示是该层的第几个子节点):
题目九
开发一个系统帮助业务部门实现灵活的奖金计算。对于普通员工,主要有个人当月业务奖金、个人当月回款奖金等,对于部门经理,除了有普通员工的奖金外,还有团队当月业务奖金等。目前各奖金类别的计算规则如下:
个人当月业务奖金 = 个人当月销售额 * 3%
个人当月回款奖金 = 个人当月回款额 * 0.1%
团队当月业务奖金 = 团队当月销售额 * 1%
考虑到业务部门要通过调整奖金计算方式来激励士气,系统应灵活地适应各种需求变化,例如,将来可能会增加个人业务增长奖金、团队当月回款奖金、团队业务增长奖金、团队盈利奖金等奖金类别,也可能增加新的员工岗位,或变更奖金计算规则等。请写出你所选择的设计模式,画出类图,并给出核心代码。
此题原博客
对于这道题里的奖金计算,最痛苦的是这些奖金的计算方式会经常发生变动,在运行期间,不同人员参与的奖金计算方式也是不同的,除了参与个人计算部分外,还要参加团队奖金的计算,这就意味着需要在运行期间动态来组合需要计算的部分,也就是会有一堆的if-else;甚至会有新的需求,这就要求我们的设计实现要足够灵活,要能够很快进行相应调整和修改。
那么上面的要求该如何实现呢?
- 一种方案是通过继承来扩展功能;
- 另外一种方案就是到计算奖金的对象里面,添加或者删除新的功能,并在计算奖金的时候,调用新的功能或是不调用某些去掉的功能,但这种方案会严重违反开-闭原则。
总结一下,我们目前奖金计算面临的问题有: - (1)计算逻辑复杂
- (2)要有足够灵活性,可以方便的增加或者减少功能
- (3)要能动态的组合计算方式,不同的人参与的计算不同
然后我们把上面的问题抽象一下,假设有一个计算奖金的对象,现在需要能够透明的给它增加和减少功能,还需要能够动态的组合功能,每个功能就相当于在计算奖金的某个部分。而这就跟装饰模式契合了起来。
装饰模式:动态的给一个对象添加一些额外的职责。
而透明的意思是:给一个对象增加功能,又不让这个对象知道,也不去改动这个对象。
在装饰模式的实现中,通过定义一个抽象类,让这个类实现与被装饰对象相同的接口(这样就不影响原先与被装饰对象交接的其他对象),然后在具体实现类里面,转调被装饰的对象,也就是在转调的前后添加新的功能(这样来看,外部接口经过打包看似一致,但内里的代码悄然变化)——所以叫装饰模式。
并且在转调的时候,如果觉得被装饰的对象的功能不再需要了,还可以直接替换掉,也就是不再转调,而是在装饰对象里面完全全新的实现。
装饰模式的结构图一般是这样的,我们试着带入这道题一起分析:
- Component:组件对象的接口,可以给这些对象动态的添加职责。(这道题里面我们可以在这个接口里面定义计算奖金的业务方法,因为外部就是使用这个接口来操作装饰模式构成的对象结构中的对象)
- ConcreteComponent:具体的组件对象,实现组件对象接口,通常就是被装饰器装饰的原始对象,也就是可以给这个对象添加职责。(对标本题就是添加一个基本的实现组件接口的对象,比如让它返回奖金为0,反正可以重写)
- Decorator:所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象,其实就是持有一个被装饰的对象(注意这个被装饰的对象不一定是最原始的那个对象了,也可能是被其它装饰器装饰过后的对象,反正都是实现的同一个接口,也就是同一类型)
- ConcreteDecorator:实际的装饰器对象,实现具体要向被装饰对象添加的功能。(把各个计算奖金的规则实现成为具体的装饰器对象)
//计算奖金的组件接口
public abstract class Component {
/**
* 计算某人在某段时间内的奖金,有些参数在演示中并不会使用,
* 但是在实际业务实现上是会用的,为了表示这是个具体的业务方法,
* 因此这些参数被保留了
* @param user 被计算奖金的人员
* @param begin 计算奖金的开始时间
* @param end 计算奖金的结束时间
* @return 某人在某段时间内的奖金
*/
public abstract double calcPrize(String user,Date begin,Date end);
}
//业务接口提供一个基本的实现ConcreteComponent类
public class ConcreteComponent extends Component{
public double calcPrize(String user, Date begin, Date end) {
//只是一个默认的实现,默认没有奖金
return 0;
}
}
//定义抽象的装饰器:定义所有装饰器对象需要实现的方法
public abstract class Decorator extends Component{
//持有被装饰的组件对象
protected Component c;
/*通过构造方法传入被装饰的对象
* @param c被装饰的对象
*/
public Decorator(Component c){
this.c = c;
}
public double calcPrize(String user, Date begin, Date end) {
//转调组件对象的方法
return c.calcPrize(user, begin, end);
}
}
//定义一系列具体的装饰器对象,每一个都可以实现一条计算奖金的规则,现在有三条计算奖金的规则,那就对应有三个装饰器对象来实现,依次来看看它们的实现。
//装饰器对象①:计算个人当月业务奖金
public class MonthPrizeDecorator extends Decorator{
public MonthPrizeDecorator(Component c){
super(c);
}
public double calcPrize(String user, Date begin, Date end) {
//1:先获取前面运算出来的奖金
double money = super.calcPrize(user, begin, end);
//2:然后计算当月业务奖金,按人员和时间去获取当月业务额,然后再乘以3%
double prize = TempDB.mapMonthSaleMoney.get(user) * 0.03;
System.out.println(user+"当月业务奖金"+prize);
return money + prize;
}
}
//装饰器对象②:计算个人回款奖金
public class SumPrizeDecorator extends Decorator{
public SumPrizeDecorator(Component c){
super(c);
}
public double calcPrize(String user, Date begin, Date end) {
//1:先获取前面运算出来的奖金
double money = super.calcPrize(user, begin, end);
//2:然后计算累计奖金,其实应按人员去获取累计的业务额,然后再乘以0.1%
//简单演示一下,假定大家的累计业务额都是1000000元
double prize = 1000000 * 0.001;
System.out.println(user+"累计奖金"+prize);
return money + prize;
}
}
//装饰器对象③:计算当月团队业务奖金
public class GroupPrizeDecorator extends Decorator{
public GroupPrizeDecorator(Component c){
super(c);
}
public double calcPrize(String user, Date begin, Date end) {
//1:先获取前面运算出来的奖金
double money = super.calcPrize(user, begin, end);
//2:然后计算当月团队业务奖金,先计算出团队总的业务额,然后再乘以1%
//假设都是一个团队的
double group = 0.0;
for(double d : TempDB.mapMonthSaleMoney.values()){
group += d;
double prize = group * 0.01;
System.out.println(user+"当月团队业务奖金"+prize);
return money + prize;
}
}
/*使用装饰器的客户端*/
public class Client {
public static void main(String[] args) {
//先创建计算基本奖金的类,这也是被装饰的对象
Component c1 = new ConcreteComponent();
/*然后对计算的基本奖金进行装饰,这里要组合各个装饰
*说明,各个装饰者之间最好是不要有先后顺序的限制,
*也就是先装饰谁和后装饰谁都应该是一样的*/
//先组合普通业务人员的奖金计算
Decorator d1 = new MonthPrizeDecorator(c1);
Decorator d2 = new SumPrizeDecorator(d1);
//注意:这里只需使用最后组合好的对象调用业务方法即可,会依次调用回去
//日期对象都没有用上,所以传null就可以了
double zs = d2.calcPrize("张三",null,null);
System.out.println("==========张三应得奖金:"+zs);
double ls = d2.calcPrize("李四",null,null);
System.out.println("==========李四应得奖金:"+ls);
//如果是业务经理,还需要一个计算团队的奖金计算
Decorator d3 = new GroupPrizeDecorator(d2);
double ww = d3.calcPrize("王五",null,null);
System.out.println("==========王经理应得奖金:"+ww);
}
}
输出:
装饰模式感觉就有点像做菜,最开始拿着生肉,这就是原始的需要装饰的对象,然后我想把它煮熟,那煮熟这个操作就是一次对原有对象的修饰,煮肉用的开水和容器就可以封装成一个装饰器对象,生肉送进去,等几秒,诶,就熟了;然后煮熟(装饰一回)后我觉得没味道,加点酱油啊,这就是又一次的装饰,而此时的对象就不再是生肉了,变成了煮熟的熟肉,所以一道菜上桌是一层层buff的叠加,最后变成人间美味。
这道题里层层递进的关系就可以这么表示:
题目十
请设计一个电子相册自动生成程序,要求该程序能够将一组图片自动生成到一个以树形结构保存的电子相册中,相册的目录采用树形结构,一级目录为年,二级目录为月,三级目录为日。每张照片可以添加音效和花边等特效。请写出你所选择的设计模式,画出类图,并给出核心代码
这道题我们老师给的答案是:组合模式+装饰模式
最后一道题了,加油加油!
这道题要求其实就是分类,能够将一组图片按照时间进行相应的划分,初步决定用组合模式(因为是树形结构,抽象接口是一组照片,树枝结构容器在这里就是年、月、日,树叶结构就是图片)+ 单例模式(每一年每一个月每一天对应的文件夹肯定只用创建一个)
uml类图:
import java.util.ArrayList;
import java.util.List;
public class PicTime {
public static int[] year = {0,0,0};
public static int[] month = {0,0,0};
public static int[] day = {0,0,0};
protected static List<PicTime> pt = new ArrayList();
private PicTime pc =null;
public int name;
//构造方法私有化,便于实现单例模式
protected PicTime() {};
//flag0用于标记是年0、月1、日2
//flag1用于记录当前的年份/月份/日期
public PicTime Create() {
if(pc==null) {
pc = new PicTime();
}
return pc;
}
public void show() {
for(int i=0;i<pt.size();i++) {
System.out.println("包含有:");
PicTime temp = pt.get(i);
temp.show();
}
}
public void add(PicTime py) {
py.add(py);
}
}
class PicYear extends PicTime{
private PicYear py =null;
//构造方法私有化,便于实现单例模式
private PicYear() {};
public PicTime Create(int years) {
if(super.year[years]==0) {
super.year[years]=1;
py = new PicYear();
this.name=years;
}
return py;
}
public void show() {
System.out.println("——此为一级目录:"+ name +"年");
for(int i=0;i<pt.size();i++) {
System.out.println("包含有:");
PicTime temp = this.pt.get(i);
temp.show();
}
}
}
class PicMonth extends PicTime{
private PicMonth pm =null;
//构造方法私有化,便于实现单例模式
private PicMonth() {};
public PicTime Create(int months) {
if(super.month[months]==0) {
super.month[months]=1;
pm = new PicMonth();
this.name=months;
}
return pm;
}
public void show() {
System.out.println("————此为二级目录:"+name+"月");
for(int i=0;i<pt.size();i++) {
System.out.println("包含有:");
PicTime temp = this.pt.get(i);
temp.show();
}
}
}
class PicDay extends PicTime{
private PicDay pd =null;
public List<Picture> pic = new ArrayList();
//构造方法私有化,便于实现单例模式
private PicDay() {};
public PicTime Create(int days) {
if(super.day[days]==0) {
super.day[days]=1;
pd = new PicDay();
this.name=days;
}
return pd;
}
public void add(Picture pc) {
pic.add(pc);
}
public void show() {
System.out.println("————此为三级目录:"+ name +"日");
for(int i=0;i<pt.size();i++) {
System.out.println("包含有:");
PicTime temp = this.pt.get(i);
temp.show();
}
}
}
public class Picture {
private String picName;
private String year;
private String month;
private String day;
public Picture(String name,String year,String month,String day) {
this.picName=name;
this.year=year;
this.month=month;
this.day=day;
}
public show() {
System.out.println("此为存储的图片"+picName);
}
public void PicMusic() {
System.out.println("已给"+ picName +"增加音效!");
}
public void PicFlowers() {
System.out.println("已给"+ picName +"增加花边特效!");
}
public void Other() {
//其他特效
}
}
最后
以上就是搞怪八宝粥为你收集整理的吉林大学设计模式第三次作业(下)题目六题目七题目八题目九题目十的全部内容,希望文章能够帮你解决吉林大学设计模式第三次作业(下)题目六题目七题目八题目九题目十所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复