找到这里的多半是我的学弟学妹了,怎么说呢,希望能帮到你们吧,也更希望我留在这里的思路和代码是你们的下限,设计模式真的很精妙,祝你们有所增益。
题目一
请为一校服制造厂编写一个校服生产子系统。
该工厂可为多家学校生产校服,包括秋季校服和夏季校服。一套秋季校服含一件长袖上衣和一条秋季长裤,一套夏季校服含一件短袖衬衣、一件短袖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();
}
}
输出: