吉林大学设计模式第二次作业

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


题目一

请为一校服制造厂编写一个校服生产子系统。
该工厂可为多家学校生产校服,包括秋季校服和夏季校服。一套秋季校服含一件长袖上衣和一条秋季长裤,一套夏季校服含一件短袖衬衣、一件短袖T恤、一条夏季长裤和一条短裤。
不同学校校服款式不同。请设计一个子系统为三所学校(一中、二中、三中)分别生产秋季校服和夏季校服(均码)。
例如,当用户输入“一中+夏季”时,系统就会生产出一套一中夏季校服;当用户输入“一中+秋季”时,系统生产出一套一中秋季校服。
请写出你所选择的设计模式,画出类图,并给出核心代码。

答案:

请添加图片描述
这道题我选择的是抽象工厂模式,也就是根据产品种类,客户端需求去判断生成对应的类。
我把衣服相关的都放在一个clothes中去实现,学校的实现分为一中、二中和三中,看了上面的uml相信我也不用多说什么了,这道题比较简单,我感觉自己对面对对象编程有点感觉了,不过自己看了看写的代码,挺多地方都不规范,下次注意。

public class Clothes {
    
    
	public void fallShirt() {
    
    
		System.out.print("+ 秋季长袖");
	}
	public void fallTrousers() {
    
    
		System.out.print("+ 秋季长裤");
	}
	public void summerShorts() {
    
    
		System.out.print("+ 夏季短裤子");
	}
	public void summerShortSleevedShirt() {
    
    
		System.out.print("+ 夏季短袖衬衣");
	}
	public void summerTrousers() {
    
    
		System.out.print("+ 夏季长裤");
	}
	public void summerTShirt() {
    
    
		System.out.print("+ 夏季短袖T恤");
	}
}

class School {
    
    
    public void showSchool() {
    
    }
}

class School1 extends School{
    
    
	public void showSchool() {
    
    
		System.out.println("一中:");
	}
}

class School2 extends School{
    
    
	public void showSchool() {
    
    
		System.out.println("二中:");
	}
}

class School3 extends School{
    
    
	public void showSchool() {
    
    
		System.out.println("三中:");
	}
}

package homework2;

class Season {
    
    
    public Clothes clothes;
    public void getClothes() {
    
    	   
    }
}

class Autumn extends Season{
    
    
	public Clothes clothes;
	public Autumn() {
    
    
		clothes = new Clothes(); 
	}
	public void getClothes() {
    
    	 
		clothes.fallShirt();
		clothes.fallTrousers();
    }
}

class Summer extends Season{
    
    
	public Clothes clothes;
	public Summer() {
    
    
		clothes = new Clothes(); 
	}
	public void getClothes() {
    
    
		clothes.summerTShirt();
		clothes.summerShortSleevedShirt();
		clothes.summerTrousers();
		clothes.summerShorts();
	}
}


import java.util.Scanner;

public class Uniform {
    
    
    
	public static void main(String[] args) {
    
    
		 
		 Scanner sc = new Scanner(System.in);
         System.out.println("请输入当前需求:");
         String in = sc.nextLine();
         //“+”需要转义
         String[] split = in.split("\\+");
//         System.out.println(split[0]);
//         System.out.print(split[1]);
         if(split[0].equals("一中")) {
    
    
        	 School1 s1 = new School1();
        	 s1.showSchool();
         }else if(split[0].equals("二中")) {
    
    
        	 School2 s2 = new School2();
        	 s2.showSchool();
         }else if(split[0].equals("三中")) {
    
    
        	 School3 s3 = new School3();
        	 s3.showSchool();
         }
         
         
         if(split[1].equals("夏季")) {
    
    
        	 Summer season = new Summer();
        	
        	 season.getClothes();
         }
         if (split[1].equals("秋季")) {
    
    
        	 Autumn season = new Autumn();
        	 season.getClothes();      	 
         }
	}

}


输出是这样的:

请添加图片描述
请添加图片描述


题目二

小王正在设计一个导出数据的应用框架。客户要求:导出数据可能存储成不同的文件格式,例如:文本格式、数据库备份形式、Excel格式、Xml格式等等,并且,不管什么格式,导出数据文件都分成三个部分,分别是文件头、文件体和文件尾。
在文件头部分,需要描述如下信息:分公司或门市点编号、导出数据的日期,对于文本格式,中间用逗号分隔。
在文件体部分,需要描述如下信息:表名称、然后分条描述数据,对于文本格式,表名称单独占一行,数据描述一行算一条数据,字段间用逗号分隔。
在文件尾部分,需要描述如下信息:输出人。
请写出你所选择的设计模式,画出类图,并给出核心代码。

分析这道题,它其实自己也说了,尽管文件格式不同,但都分为了三个部分,并按照一定的步骤呈现。所以我觉得这道题可以使用建造者模式,其相关的定义为:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。

其实感觉这里和上面那道题的抽象工厂模式有点像,不过再抽象一下的话,建造者模式和工厂模式的关注点不同——建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程。
建造者模式由产品、抽象建造者、具体建造者、指挥者等 4 个要素构成,在这道题里面(括号里是我抄的相关定义帮助自己理解):

  • 产品:就是文件的三个部分(它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。)
  • 抽象建造者:我写了一个接口类interface Builder,里面的三个方法控制文件三个部分的生成(它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 )
  • 具体建造者:我定义了一个 Operate类,并且其中的方法控制了文件的一些实现细节,比如这道题里说的逗号分隔和换行 (实现Builder 接口,完成复杂产品的各个部件的具体创建方法)
  • 指挥者:也就是我们的Client端了,(它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息)

请添加图片描述

public class File {
    
    
	protected String file_type="text";
	public String get_type(){
    
    
		return file_type;
	}
	public int set_type(String settype) {
    
    
		file_type = settype;
		return 0;
	}
	///文件头开始:
	public void number() {
    
    
		System.out.print("分公司或门市点编号");
	}
	public void date() {
    
    
		System.out.print("导出数据的日期");
	}
	/*public void file_head() {
		System.out.println("分公司或门市点编号、导出数据的日期");
		//这样写在一起无法应对文本格式添加逗号的要求
	}*/
	///文件头结束
	
	///文件体开始
	public void table_name() {
    
    
		System.out.print("表名称");
	}
	public void describe() {
    
    
		System.out.print("分条描述数据");
	}
	/*
	public void file_body() {
		System.out.println("表名称、然后分条描述数据");
	}*/
	///文件体结束
	
	///文件尾开始
	public void file_tail() {
    
    
		System.out.println("输出人:");
	}
	///文件尾结束


}

public interface Builder {
    
    
	public void head() ;
	public void body() ;
	public void tail() ;
}

public class Operate extends File implements Builder {
    
    
	public void head() {
    
    
		System.out.print("输出文件头");
		super.number();
		if(get_type().equals("text")) {
    
    
			System.out.print(",");
		}
		super.date();
	}
	public void body() {
    
    
		System.out.print("输出文件体");
		//super.file_body();
		super.table_name();
		if(get_type().equals("text")) {
    
    
			System.out.println(" ");//另起一行
		}
		super.describe();
		if(get_type().equals("text")) {
    
    
			System.out.print(",");
		}
	}
	public void tail() {
    
    
		System.out.print("输出文件尾");
		super.file_tail();
	}
}

public class Client {
    
    
	public static void main(String[] args) {
    
    
		//System.out.println("hello word");
		// 首先创建出一个输出文件的机器人->robot
		Builder robot=new Operate();
		robot.head();
		robot.body();
		robot.tail();
	}
}

题目三

在下面的TicketMaker类(见下表)中,每次调用getNextTicketNumber方法都会返回1000,1001,1002…的数列。我们可以用它生成票的编号或是其他序列号。在现在该类的实现方式下,我们可以生成多个该类的实例。请修改代码,确保只能生成一个该类的实例。

在这里插入图片描述

这道题非常简单,按照要求使用的是单例模式(保证一个类仅有一个实例,并提供一个访问它的全局访问点)

public class TicketMaker {
    
    
	//创建 SingleObject 的一个对象
	   private static TicketMaker countTicket;
	   private static int ticket =1000;
	   //让构造函数为 private,这样该类就不会被实例化
	   private TicketMaker(){
    
    }
	 
	   //获取唯一可用的对象
	   public static TicketMaker getNextTicketNumber(){
    
    
		  if(countTicket == null) {
    
    
			  countTicket = new TicketMaker();
		  }
		  ticket+=1;
	      return countTicket;
	   }
	 
	   public void showMessage(){
    
    
	      System.out.println(countTicket.ticket);
	   }
	      
	public static void main(String[] args) {
    
    

	      //获取唯一可用的对象
		for(int i = 0; i<10 ; i++) {
    
    
		  TicketMaker object = TicketMaker.getNextTicketNumber();
		  object.showMessage();
		}
	}
}

这是输出:
请添加图片描述


题目四

小王正在编写一个简单的计算器程序,要求输入两个整数和运算符号(加、减、乘、除),输出计算结果。小王用面向过程方法编写了下面的代码。请采用面向对象方法通过恰当的设计模式对小王的代码进行重构。

int main() {
    
    
  int numa,numb; char oper; double result;
  cin>>numa>>numb;  cin>>oper;
  switch(oper) {
    
    
    case '+': result=numa+numb; break;
    case '-': result=numa-numb; break;
    case '*': result=numa*numb; break;
    case '/': result=numa/(double)numb; break;
  }
  cout<<result<<endl;
  return 0;
}

哈哈哈这是大鸟小菜书上的一个情景欸!
首先分析源代码哪里有问题(问题大大的!):

  • 除法判别里如果numb为0,这种错误没有处理
  • 之前讲到过业务逻辑一定要分装实现接口隔离原则和单一职责原则,在这段简单的代码里,计算功能和显示功能杂糅到了一起,这很不好(但这道题好像没要求输出设备,所以这里的改进就暂且先不考虑输出单独包装)
  • 这个计算器太逊了,如果日后要新增开根号等运算,需要不断增加case改动现有代码,所以最好每个运算有个公共的父类,并使用简单工厂模式,在实际解决时去实例化相应的运算类对象。

使用的模式是简单工厂模式,根据需求实例化相应的运算类。

#include <iostream>
#include<string>
using namespace std;
 
//运算类的父类 
class Calculate{
    
    
public:
    Calculate(){
    
    };
    int result;
    int alu(){
    
    return result;}
};

//实现加法运算 
class add : public Calculate
{
    
    
public:
    add(int x,int y){
    
    result=x+y;}
};

//实现减法运算 
class sub:public Calculate
{
    
    
public:
    sub(int x,int y){
    
    result=x-y;}
};

//实现乘法运算 
class mul:public Calculate{
    
    
public:
    mul(int x,int y){
    
    result=x*y;}
};

//实现除法运算 
class chu:public Calculate{
    
    
public:
    chu(int x,int y){
    
    
    	int b=y;
    	if(b==0){
    
    
            	cout<<"除数为0,请重新输入!"<<endl;
            	cin>>b;
			}
	    result=x/b;
	}
};

//采用简单工厂模式,根据需求实例化对应的运算类 
class Calculate_Factory
{
    
    
public:
    Calculate_Factory(){
    
    };
    Calculate* produce(char method,int a,int b){
    
    
        if(method=='+'){
    
    
            cout<<"运算方法:加法"<<endl;
            return new add(a,b);
        }
        else if(method=='-')
        {
    
    
            cout<<"运算方法:减法"<<endl;
            return new sub(a,b);
        }
        else if(method=='*')
        {
    
    
            cout<<"运算方法:乘法"<<endl;
            return new mul(a,b);
        }else if(method=='/')
        {
    
    
            cout<<"运算方法:除法"<<endl;   
            return new chu(a,b);
        }
        else
            cout<<"无法识别运算方法"<<endl;
    }
};
int main()
{
    
    
    int numa,numb;
    char oper;
    double result;
    cin>>numa>>numb;
    cin>>oper;
    Calculate_Factory* factory = new Calculate_Factory();
    result=factory->produce(oper,numa,numb)->alu();
    cout<<result<<endl;
    return 0;
}

题目五

请你按照单例模式的思想,重新实现下面给出的DBConnections类,确保系统中该类的实例对象最多只能存在三个。

class DBConnections {
    
    

public:

   DBConnections ( ) {
    
     ... } 

   ~ DBConnections ( ) {
    
     ... }

   void ConnectionInfo ( ) {
    
     ... }

 };

答案分析:

单例模式,构造方法私有化,同时注意使用static静态方法和参数:

package homework2_5;

public class DBConnections {
    
    
	private static DBConnections temp=null;
	private static int count=0;
	private DBConnections(){
    
    }
	public static DBConnections ConnectionInfo () {
    
    
		if(count<3) {
    
    
			temp = new DBConnections();
		    count++;
		    System.out.println("这是第 "+count+"个对象" );
		}
		if(count>=3)
			System.out.println("该类不可再实例化!" );
		return temp;
	}

	public static void main(String[] args) {
    
    
		DBConnections object = null;
		// TODO Auto-generated method stub
		for(int i=0;i<10;i++)
			object = DBConnections.ConnectionInfo();
	}
}

输出:

请添加图片描述

猜你喜欢

转载自blog.csdn.net/KQwangxi/article/details/120900241