BLOG-3_JavaHomework_Summary

前言

小总结

第六次PTA作业开始了新的篇章----电信计费系列,由于吸取了之前的教训,所以每次的作业都要考虑可拓展性,虽然这个系列也用到了正则表达式,但是有之前的铺垫,已经能从容面对了,总的来说,相对之前的作业而言,有了更多的思考,更深入的理解了OO。

设计与分析

多态测试

题目简述:

输入立方体或圆柱体的信息,输出所有图形的表面积之和、体积之和

代码

import java.util.Scanner;

public class Main {
   	public static int cnt;

   	public static void main(String[] args) {
           Scanner in = new Scanner(System.in);
           String s;
           Container[] containers = new Container[1000];
           cnt = in.nextInt();
           for (int i = 0; i < cnt; i++) {
               s = in.next();
               if ("cube".equals(s)) {
                   containers[i] = new Cube(in.nextDouble());
               } else {
                   containers[i] = new Cylinder(in.nextDouble(), in.nextDouble());
               }
           }
           System.out.printf("%.2f\n", Container.sumofArea(containers));
           System.out.printf("%.2f\n", Container.sumofVolume(containers));
       }
}

interface Container {
       double pi = 3.1415926;
       double area();
       double volume();

       static double sumofArea(Container[] c) {
           double sum = 0;
           for (int i = 0; i < Main.cnt; i++) sum += c[i].area();
           return sum;
       }

       static double sumofVolume(Container[] c) {
           double sum = 0;
           for (int i = 0; i < Main.cnt; i++) sum += c[i].volume();
           return sum;
       }
   }

   class Cylinder implements Container {
       private final double radius;
       private final double high;

       public Cylinder(double radius, double high) {this.radius = radius;this.high = high;}
   
       @Override
       public double area() {return 2 * pi * radius * radius + high * 2.0 * pi * radius;}

       @Override
       public double volume() {return pi * radius * radius * high;}
   }

   class Cube implements Container {
       private final double sideLength;

       public Cube(double sideLength) {this.sideLength = sideLength;}
   
       @Override
       public double area() {return sideLength * sideLength * 6.0;}
   
       @Override
       public double volume() {return sideLength * sideLength * sideLength;}
}

分析

既然题目已经提醒要用多态了,那么就要考虑什么时候可以用到多态,很明显,题目有两种图形,但是输出却是两种图形数据的和
所以我们考虑有让两个图形都实现一个共同的Container接口,使得Container在遍历容器求和时,通过多态可以让两种图形分别报出自己的数据。

sdut-Collection-sort--C~K的班级(II)

题目简述:

输入若干学生信息,输出去重后的学生信息

代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Scanner;

public class Main {
       public static void main(String[] args) {
           Scanner in = new Scanner(System.in);
           HashSet<Stud> studs = new HashSet<>();
           int t = in.nextInt();
           for (int i = 0; i < t; i++) {
               studs.add(new Stud(in.next(), in.next(), in.next(), in.next()));
           }
           System.out.println(studs.size());
           ArrayList<Stud> studsArr = new ArrayList<>(studs);
           Collections.sort(studsArr);
           for (Stud s : studsArr) System.out.println(s);
       }
   }

   class Stud implements Comparable<Stud>{
       String id, name, age, sex;

       public Stud(String id, String name, String age, String sex) {
           this.id = id;
           this.name = name;
           this.age = age;
           this.sex = sex;
       }
       @Override
       public int hashCode() {return Integer.parseInt(id);}
       @Override
       public boolean equals(Object obj) {return id.equals(((Stud) obj).id);}
       @Override
       public String toString() {return id + " " + name + " " + age + " " + sex;}
       @Override
       public int compareTo(Stud o) {return Integer.compare(Integer.parseInt(id), Integer.parseInt(o.id));}
}

分析

说到去重,很明显,可以用HashSet来完成

使用HashSet需要重写hashCode()equals()

@Override
public int hashCode() {
	return Integer.parseInt(id);
}
@Override
public boolean equals(Object obj) {
	return id.equals(((Stud) obj).id);
}

由于每个学生的学号是唯一的,那么我们可以将学号作为每个学生的HashCode,那么equals也同理

题目还提到排序

这需要让学生的类实现Comparable接口,将HashSet放入到链表,然后调用Collections.sort()对链表进行排序后,遍历输出,便是有序的

编写一个类Shop(商店)、内部类InnerCoupons(内部购物券)

题目简述:

商店类有内部类购物券,商店有面额为100,50的购物券,输入牛奶箱数,输出使用什么购物券买牛奶,以及牛奶剩余

代码

import java.util.Scanner;

public class Main {
       public static void main(String[] args) {
           Scanner in = new Scanner(System.in);
           Shop myshop = new Shop(in.nextInt(), 50, 100);
           myshop.buy();
       }
}

class Shop {
       private int milkCount;
       private InnerCoupons coupons50;
       private InnerCoupons coupons100;

       class InnerCoupons {
           public int value;
           public InnerCoupons(int value) {this.value = value;}
       
           public void buy() {
               System.out.println("使用了面值为" + value + "的购物券进行支付");
               setMilkCount(getMilkCount() - value / 50);
               System.out.println("牛奶还剩" + getMilkCount() + "箱");
           }
       }
       public void buy(){
           coupons50.buy();
           coupons100.buy();
       }

       public Shop(int milkCount, int coupons50, int coupons100) {
           this.milkCount = milkCount;
           this.coupons50 = new InnerCoupons(coupons50);
           this.coupons100 = new InnerCoupons(coupons100);
       }
       public int getMilkCount() {return milkCount;}
       public void setMilkCount(int milkCount) {this.milkCount = milkCount;}
}

分析

题目要求用内部类,根据题目要求完成即可

动物发声模拟器(多态)

题目简述:

用多态输出猫、狗、山羊的类型以及叫声

代码

//动物发生模拟器.  请在下面的【】处添加代码。
public class Main {
       public static void main(String[] args) {
           Cat cat = new Cat();
           Dog dog = new Dog();
           Goat goat = new Goat();
           speak(cat);
           speak(dog);
           speak(goat);
       }

       //定义静态方法speak()
       public static void speak(Animal animal) {
           System.out.print(animal.getAnimalClass() + "的叫声:");
           animal.shout();
       }
}

//定义抽象类Animal
abstract class Animal {
       abstract String getAnimalClass();
       abstract void shout();
   }

   //基于Animal类,定义猫类Cat,并重写两个抽象方法
   class Cat extends Animal {
   
       @Override
       String getAnimalClass() {return "猫";}
       @Override
       void shout() {System.out.println("喵喵");}
   }

   //基于Animal类,定义狗类Dog,并重写两个抽象方法
   class Dog extends Animal {
   
       @Override
       String getAnimalClass() {return "狗";}
       @Override
       void shout() {System.out.println("汪汪");}
   }

   //基于Animal类,定义山羊类Goat,并重写两个抽象方法
   class Goat extends Animal {

       @Override
       String getAnimalClass() {return "山羊";}
       @Override
       void shout() {System.out.println("咩咩");}
}

分析

题目要求用到多态,根据题目提示完成即可

电信计费系列1、系列2-手机+座机计费、系列3-短信计费

题目简述:

输入若干用户和其通讯记录,输出用户话费余额

代码

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
 * Main程序入口
 * 职责:输入数据,将正确的信息存入InputData,*/
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        HashSet<User> userSet = new HashSet<>();
        ArrayList<CommunicationRecord> communicationRecords = new ArrayList<>();
        String Line;
        do {
            Line = in.nextLine();
            if (Line.equals("")) continue;
            if (Line.charAt(0) == 'u') {
                String[] uData = InputFormat.input_u_Format(Line);
                if (uData != null) userSet.add(new User(uData[1], uData[2].charAt(0) - '0'));
            } else if (Line.charAt(0) == 't') {
                CallRecord tempCallRecord = InputFormat.input_t_Format(Line);
                if (tempCallRecord != null) communicationRecords.add(tempCallRecord);
            } else if (Line.charAt(0) == 'm') {
                String[] mData = InputFormat.input_m_Format(Line);
                if (mData != null) communicationRecords.add(new MessageRecord(mData[0], mData[1], mData[2]));
            }
        } while (!"end".equals(Line));
        ArrayList<User> users = new ArrayList<>(userSet);
        DataCentre dataCentre = new DataCentre(users, communicationRecords);
        dataCentre.printUserCosts();
    }
}

/*
 * CommunicationRecord通讯记录
 * 由主动用户与应答用户为基本,电话,短信等方式构成*/
abstract class CommunicationRecord {
    String callingNumber, answerNumber;

    public CommunicationRecord(String callingNumber, String answerNumber) {
        this.callingNumber = callingNumber;
        this.answerNumber = answerNumber;
    }

    public CommunicationRecord() {

    }

    public String getCallingNumber() {
        return callingNumber;
    }

    public String getAnswerNumber() {
        return answerNumber;
    }

}

class LandlinePhoneCharging extends ChargeMode {

    public LandlinePhoneCharging() {
        getChargeRules().add(new LandPhoneInCityRule());
        getChargeRules().add(new LandPhoneInProvinceRule());
        getChargeRules().add(new LandPhoneInLandRule());
    }

    @Override
    double calCost(UserRecords userRecords) {
        double cost = 0;
        for (ChargeRule chargeRule : getChargeRules())
            cost += (chargeRule instanceof CallChargeRule) ? ((CallChargeRule) chargeRule).calCost(userRecords) : 0;
        return cost;
    }

    @Override
    double getMonthlyRent() {
        return 20;
    }
}
class PhoneMessage extends ChargeMode {
    private double monthlyRent = 0;

    public PhoneMessage() {
        getChargeRules().add(new SendMessageRule());
    }

    @Override
    double calCost(UserRecords userRecords) {
        double cost = 0;
        for (ChargeRule chargeRule : getChargeRules())
            cost += (chargeRule instanceof SendMessageRule) ? ((SendMessageRule) chargeRule).calCost(userRecords) : 0;
        return cost;
    }

    @Override
    double getMonthlyRent() {
        return monthlyRent;
    }
}
class PhoneCharging extends ChargeMode {
    private double monthlyRent = 15;

    public PhoneCharging() {
        getChargeRules().add(new PhoneInCityRule());
        getChargeRules().add(new PhoneInProvinceRule());
        getChargeRules().add(new PhoneInLandRule());
        getChargeRules().add(new PhoneAnsInLandRule());
        getChargeRules().add(new SendMessageRule());
    }

    @Override
    double calCost(UserRecords userRecords) {
        double cost = 0;
        for (ChargeRule chargeRule : getChargeRules())
            cost += (chargeRule instanceof CallChargeRule) ? ((CallChargeRule) chargeRule).calCost(userRecords) : (chargeRule instanceof SendMessageRule) ? ((SendMessageRule) chargeRule).calCost(userRecords) : 0;
        return cost;
    }

    @Override
    double getMonthlyRent() {
        return monthlyRent;
    }
}

class UserRecords {
    private ArrayList<CallRecord> callingInCityRecords = new ArrayList<>();
    private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<>();
    private ArrayList<CallRecord> callingInLandRecords = new ArrayList<>();

    private ArrayList<CallRecord> answerInCityRecords = new ArrayList<>();
    private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<>();
    private ArrayList<CallRecord> answerInLandRecords = new ArrayList<>();

    private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<>();
    private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>();

    public ArrayList<CallRecord> getCallingInCityRecords() {
        return callingInCityRecords;
    }

    public ArrayList<CallRecord> getCallingInProvinceRecords() {
        return callingInProvinceRecords;
    }

    public ArrayList<CallRecord> getCallingInLandRecords() {
        return callingInLandRecords;
    }

    public ArrayList<CallRecord> getAnswerInCityRecords() {
        return answerInCityRecords;
    }

    public ArrayList<CallRecord> getAnswerInProvinceRecords() {
        return answerInProvinceRecords;
    }

    public ArrayList<CallRecord> getAnswerInLandRecords() {
        return answerInLandRecords;
    }

    public ArrayList<MessageRecord> getSendMessageRecords() {
        return sendMessageRecords;
    }

    public ArrayList<MessageRecord> getReceiveMessageRecords() {
        return receiveMessageRecords;
    }
}

abstract class ChargeMode {

    ArrayList<ChargeRule> chargeRules = new ArrayList<>();

    abstract double calCost(UserRecords userRecords);

    abstract double getMonthlyRent();

    public ArrayList<ChargeRule> getChargeRules() {
        return chargeRules;
    }
}

class MessageRecord extends CommunicationRecord {
    private String message;

    public MessageRecord(String callingNumber, String answerNumber, String message) {
        super(callingNumber, answerNumber);
        this.message = message;
    }

    public boolean isSendUser(User user) {
        return callingNumber.equals(user.getNumber());
    }

    public boolean isAnsUser(User user) {
        return answerNumber.equals(user.getNumber());
    }

    public String getMessage() {
        return message;
    }
}

/*
 * DataCentre
 * 职责:将记录与用户匹配,存用户数据*/
class DataCentre {
    private ArrayList<User> users;  //所有用户
    private ArrayList<CommunicationRecord> communicationRecords;  //所有记录

    public DataCentre(ArrayList<User> users, ArrayList<CommunicationRecord> communicationRecords) {
        this.users = users;
        this.communicationRecords = communicationRecords;
        matchingRecords();
    }

    /*根据拨出号码匹配其记录*/
    private void matchingRecords() {
        for (User user : users) {
            ArrayList<CommunicationRecord> communicationRecords = new ArrayList<>();
            for (CommunicationRecord communicationRecord : this.communicationRecords) {
                //所有拨的记录匹配到用户
                if (communicationRecord instanceof CallRecord && (user.getNumber().equals(communicationRecord.getCallingNumber())))
                    communicationRecords.add(communicationRecord);
                else if (communicationRecord instanceof MessageRecord)
                    communicationRecords.add(communicationRecord);
            }
            user.getCallRecords().addAll(communicationRecords);
        }
        for (User user : users) {
            ArrayList<CommunicationRecord> communicationRecords = new ArrayList<>();
            for (CommunicationRecord communicationRecord : this.communicationRecords) {
                //所有接的记录匹配到用户
                if (communicationRecord instanceof CallRecord && (user.getNumber().equals(communicationRecord.getAnswerNumber())))
                    communicationRecords.add(communicationRecord);
                else if (communicationRecord instanceof MessageRecord)
                    communicationRecords.add(communicationRecord);
            }
            user.getAnsRecords().addAll(communicationRecords);
        }
    }

    // 按序输出用户的当月费用
    public void printUserCosts() {
        Collections.sort(users);
        for (User user : users) {
            user.classifyRecords();
            System.out.println(user);
        }
    }

}

/*
 * ChargeRule计费规则类
 * */
class ChargeRule {

}

class LandPhoneInCityRule extends CallChargeRule {
    @Override
    public double calCost(UserRecords userRecords) {
        double cost = 0;
        for (CallRecord callRecord : userRecords.getCallingInCityRecords()) {
            int a = callRecord.getSecMinus() / 60 + callRecord.getSecMinus() % 60 > 0 ? 1 : 0;
            cost += placePerCost(callRecord) * a;
        }
        return cost;
    }

    public double placePerCost(CallRecord callRecord) {
        String ansAddress = callRecord.getAnswerAddressAreaCode();
        return InCity(ansAddress) ? 0.1 : InProvince(ansAddress) ? 0.3 : 0.6;
    }
}

class LandPhoneInProvinceRule extends CallChargeRule {
    @Override
    public double calCost(UserRecords userRecords) {
        return 0;
    }
}

class LandPhoneInLandRule extends CallChargeRule {
    @Override
    public double calCost(UserRecords userRecords) {
        return 0;
    }
}

class PhoneInCityRule extends CallChargeRule {
    @Override
    public double calCost(UserRecords userRecords) {
        double cost = 0;
        for (CallRecord callRecord : userRecords.getCallingInCityRecords()) {
            int a = callRecord.getSecMinus() / 60 + callRecord.getSecMinus() % 60 > 0 ? 1 : 0;
            cost += placePerCost(callRecord) * a;
        }
        return cost;
    }

    public double placePerCost(CallRecord callRecord) {
        String ansAddress = callRecord.getAnswerAddressAreaCode();
        return InCity(ansAddress) ? 0.1 : InProvince(ansAddress) ? 0.2 : 0.3;
    }
}

class PhoneInProvinceRule extends CallChargeRule {
    @Override
    public double calCost(UserRecords userRecords) {
        double cost = 0;
        for (CallRecord callRecord : userRecords.getCallingInProvinceRecords()) {
            int a = callRecord.getSecMinus() / 60 + callRecord.getSecMinus() % 60 > 0 ? 1 : 0;
            cost += placePerCost() * a;
        }
        return cost;
    }

    public double placePerCost() {
        return 0.3;
    }
}

class PhoneInLandRule extends CallChargeRule {
    @Override
    public double calCost(UserRecords userRecords) {
        double cost = 0;
        for (CallRecord callRecord : userRecords.getCallingInLandRecords()) {
            int a = callRecord.getSecMinus() / 60 + callRecord.getSecMinus() % 60 > 0 ? 1 : 0;
            cost += placePerCost(callRecord) * a;
        }
        return cost;
    }

    public double placePerCost(CallRecord callRecord) {
        return 0.6;
    }
}

class PhoneAnsInLandRule extends CallChargeRule {
    @Override
    public double calCost(UserRecords userRecords) {
        double cost = 0;
        for (CallRecord callRecord : userRecords.getAnswerInLandRecords()) {
            int a = callRecord.getSecMinus() / 60 + callRecord.getSecMinus() % 60 > 0 ? 1 : 0;
            cost += placePerCost(callRecord) * a;
        }
        return cost;
    }

    public double placePerCost(CallRecord callRecord) {
        return 0.3;
    }
}

class InputFormat {
    public static String[] input_u_Format(String str) {
        Matcher m = Pattern.compile("([ut])-([0-9]{11,12}) ([0-3])").matcher(str);//(u)-(0\\d{9,11}) ([0-2])
        if (m.find()) {
//            if (!numTypeLegal(m.group(2), m.group(3))) return null;
            return new String[]{m.group(1), m.group(2), m.group(3)};
        } else return null;
    }

    private static boolean numTypeLegal(String num, String type) {
        if (num.charAt(0) == '0') return num.charAt(0) == type.charAt(0);
        else if (num.charAt(0) == '1') return num.length() == 11 && (type.charAt(0) == '1' || type.charAt(0) == '2');
        else return false;
    }

    public static CallRecord input_t_Format(String str) {
        return (input_00_Format(str) != null) ? input_00_Format(str) : (input_01_Format(str) != null) ? input_01_Format(str) : (input_10_Format(str) != null) ? input_10_Format(str) : (input_11_Format(str) != null) ? input_11_Format(str) : null;
    }

    private static CallRecord input_00_Format(String str) {
        if (!input_t00_RightFormat(str)) return null;
        String[] nums = new String[2];
        int numbSplit = str.indexOf(" ", str.indexOf(" ") + 1) + 1;
        String Nums = str.substring(0, numbSplit);
        Matcher m = Pattern.compile("([ut])-([0-9]{10,12}) ([0-9]{10,12}) ").matcher(Nums);
        if (m.find()) {
            nums[0] = m.group(2);
            nums[1] = m.group(3);
        } else return null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        simpleDateFormat.setLenient(false);
        int dateSplit = str.indexOf(" ", str.indexOf(" ", numbSplit) + 1);
        String Time1 = str.substring(numbSplit, dateSplit);
        String Time2 = str.substring(dateSplit + 1);
        Date date1, date2;
        try {
            date1 = simpleDateFormat.parse(Time1);
            date2 = simpleDateFormat.parse(Time2);
        } catch (ParseException e) {
            return null;
        }
        if (date1.compareTo(date2) > 0) return null;
        return new CallRecord(nums[0], nums[1], date1, date2);
    }

    private static CallRecord input_01_Format(String str) {
        if (!input_t01_RightFormat(str)) return null;
        String[] nums = new String[3];
//        int numbSplit = str.indexOf(" ", str.indexOf(" ") + 1) + 1;
        int numbSplit = blankIdx(str, 3);
        String Nums = str.substring(0, numbSplit);
        Matcher m = Pattern.compile("([ut])-([0-9]{10,12}) ([0-9]{11,12}) (\\d+) ").matcher(Nums);
        if (m.find()) {
            nums[0] = m.group(2);
            nums[1] = m.group(3);
            nums[2] = m.group(4);
        } else return null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        simpleDateFormat.setLenient(false);
        int dateSplit = str.indexOf(" ", str.indexOf(" ", numbSplit) + 1);
        String Time1 = str.substring(numbSplit, dateSplit);
        String Time2 = str.substring(dateSplit + 1);
        Date date1, date2;
        try {
            date1 = simpleDateFormat.parse(Time1);
            date2 = simpleDateFormat.parse(Time2);
        } catch (ParseException e) {
            return null;
        }
//        if (isDate(Time1) || isDate(Time2))return null;
        if (date1.compareTo(date2) > 0) return null;

        return new CallRecord(nums[0], nums[1], nums[2], date1, date2, 1);
    }

    private static CallRecord input_10_Format(String str) {
        if (!input_t10_RightFormat(str)) return null;
        String[] nums = new String[3];
//        int numbSplit = str.indexOf(" ", str.indexOf(" ") + 1) + 1;
        int numbSplit = blankIdx(str, 3);
        String Nums = str.substring(0, numbSplit);
        Matcher m = Pattern.compile("([ut])-([0-9]{11,12}) (\\d+) ([0-9]{10,12}) ").matcher(Nums);
        if (m.find()) {
            nums[0] = m.group(2);
            nums[1] = m.group(3);
            nums[2] = m.group(4);
        } else return null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        simpleDateFormat.setLenient(false);
        int dateSplit = str.indexOf(" ", str.indexOf(" ", numbSplit) + 1);
        String Time1 = str.substring(numbSplit, dateSplit);
        String Time2 = str.substring(dateSplit + 1);
        Date date1, date2;
        try {
            date1 = simpleDateFormat.parse(Time1);
            date2 = simpleDateFormat.parse(Time2);
        } catch (ParseException e) {
            return null;
        }
        if (date1.compareTo(date2) > 0) return null;

        return new CallRecord(nums[0], nums[1], nums[2], date1, date2, 2);
    }

    private static CallRecord input_11_Format(String str) {
        if (!input_t11_RightFormat(str)) return null;
        String[] nums = new String[4];
        //        int numbSplit = str.indexOf(" ", str.indexOf(" ") + 1) + 1;
        int numbSplit = blankIdx(str, 4);
        String Nums = str.substring(0, numbSplit);
        Matcher m = Pattern.compile("([ut])-([0-9]{11,12}) (\\d+) ([0-9]{11,12}) (\\d+) ").matcher(Nums);
        if (m.find()) {
            nums[0] = m.group(2);
            nums[1] = m.group(3);
            nums[2] = m.group(4);
            nums[3] = m.group(5);
        } else return null;

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        simpleDateFormat.setLenient(false);
        int dateSplit = str.indexOf(" ", str.indexOf(" ", numbSplit) + 1);
        String Time1 = str.substring(numbSplit, dateSplit);
        String Time2 = str.substring(dateSplit + 1);
        Date date1, date2;
        try {
            date1 = simpleDateFormat.parse(Time1);
            date2 = simpleDateFormat.parse(Time2);
        } catch (ParseException e) {
            return null;
        }
        if (date1.compareTo(date2) > 0) return null;

        return new CallRecord(nums[0], nums[1], nums[2], nums[3], date1, date2);
    }

    private static int blankIdx(String str, int cnt) {
        for (int i = 0, t = 0; i < str.length(); i++) {
            if (t == cnt) return i;
            if (str.charAt(i) == ' ') t++;
        }
        return str.length();
    }

    public static String[] input_m_Format(String str) {
        Matcher m = Pattern.compile("(m)-(1[0-9]{10}) (1[0-9]{10}) ([a-z 0-9,.]+)").matcher(str);
        if (m.matches()) {
            return new String[]{m.group(2), m.group(3), m.group(4)};
        } else return null;
    }

    private static boolean input_t00_RightFormat(String str) {
        return str.matches("t-0\\d{9,11} 0\\d{9,11}( [0-9]{4}\\.(([1-9])|(1[0-2]))\\.(([1-9])|(([1|2])[0-9])|30|31) ((([0|1])[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])){2}");
    }

    private static boolean input_t01_RightFormat(String str) {
        return str.matches("t-0\\d{9,11} 1\\d{10} 0\\d{2,3}( [0-9]{4}\\.(([1-9])|(1[0-2]))\\.(([1-9])|(([1|2])[0-9])|30|31) ((([0|1])[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])){2}");
    }

    private static boolean input_t10_RightFormat(String str) {
        return str.matches("t-1\\d{10} 0\\d{2,3} 0\\d{9,11}( [0-9]{4}\\.(([1-9])|(1[0-2]))\\.(([1-9])|(([1|2])[0-9])|30|31) ((([0|1])[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])){2}");
    }

    private static boolean input_t11_RightFormat(String str) {
        return str.matches("t-1\\d{10} 0\\d{2,3} 1\\d{10} 0\\d{2,3}( [0-9]{4}\\.(([1-9])|(1[0-2]))\\.(([1-9])|(([1|2])[0-9])|30|31) ((([0|1])[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])){2}");
    }
}

/*******************************************************************
 * User调用通话记录和计费模式,
 * 通话记录只将记录分类,整理,
 * 计费模式是计费规则类的集合,计费规则只需将所有计费规则进行整理,统一计费
 * 职责:将用户按终端、记录整合
 * */
class User implements Comparable<User> {
    private UserRecords userRecords = new UserRecords();
    private ArrayList<CommunicationRecord> callRecords = new ArrayList<>();
    private ArrayList<CommunicationRecord> ansRecords = new ArrayList<>();
    private double balance = 100;
    private ChargeMode chargeMode;
    private String number;

    public User(String number, int mod) {
        this.number = number;
        switch (mod) {
            case 0: {
                chargeMode = new LandlinePhoneCharging();
                break;
            }
            case 1: {
                chargeMode = new PhoneCharging();
            }
            case 2: {

            }
            case 3: {
                chargeMode = new PhoneMessage();
            }
            default:
        }
    }

    // 话费
    public double calCost() {
        return chargeMode.calCost(userRecords);
    }

    // 余额
    public double calBalance() {
        return balance - chargeMode.getMonthlyRent();
    }

    /*将用户的所有记录分类,存于userRecords
     * */
    public void classifyRecords() {
        //拨的
        for (CommunicationRecord communicationRecord : callRecords) {
            if (communicationRecord instanceof CallRecord) {
                if (((CallRecord) communicationRecord).callInCity())
                    userRecords.getCallingInCityRecords().add((CallRecord) communicationRecord);
                else if (((CallRecord) communicationRecord).callInProvince())
                    userRecords.getCallingInProvinceRecords().add((CallRecord) communicationRecord);
                else if (((CallRecord) communicationRecord).callInLand())
                    userRecords.getCallingInLandRecords().add((CallRecord) communicationRecord);
            } else if (communicationRecord instanceof MessageRecord) {
                if (((MessageRecord) communicationRecord).isSendUser(this))
                    userRecords.getSendMessageRecords().add((MessageRecord) communicationRecord);
            }
        }
        //接的
        for (CommunicationRecord communicationRecord : ansRecords) {
            if (communicationRecord instanceof CallRecord) {
                if (((CallRecord) communicationRecord).ansInCity())
                    userRecords.getAnswerInCityRecords().add((CallRecord) communicationRecord);
                else if (((CallRecord) communicationRecord).ansInProvince())
                    userRecords.getAnswerInProvinceRecords().add((CallRecord) communicationRecord);
                else if (((CallRecord) communicationRecord).ansInLand())
                    userRecords.getAnswerInLandRecords().add((CallRecord) communicationRecord);
            } else if (communicationRecord instanceof MessageRecord) {
                if (((MessageRecord) communicationRecord).isAnsUser(this))
                    userRecords.getSendMessageRecords().add((MessageRecord) communicationRecord);
            }
        }
    }

    public UserRecords getUserRecords() {
        return userRecords;
    }

    public String getNumber() {
        return number;
    }

    public ArrayList<CommunicationRecord> getCallRecords() {
        return callRecords;
    }

    public ArrayList<CommunicationRecord> getAnsRecords() {
        return ansRecords;
    }

    @Override
    public int compareTo(User o) {
        return number.compareTo(o.getNumber());
    }

    @Override
    public int hashCode() {
        return 1;
    }

    @Override
    public boolean equals(Object obj) {
        return obj instanceof User && number.equals(((User) obj).number);
    }

    @Override
    public String toString() {
        double cost = calCost();
        double balance = calBalance() - cost;
        return getNumber() + " " + OutFormat.doubleFormat(cost) + " " + OutFormat.doubleFormat(balance);
    }
}

class CallRecord extends CommunicationRecord {
    private Date startTime, endTime;
    private String callingAddressAreaCode, answerAddressAreaCode;

    //座机互打
    public CallRecord(String callingNumber, String answerNumber, Date startTime, Date endTime) {
        super(callingNumber, answerNumber);
        this.startTime = startTime;
        this.endTime = endTime;
        callingAddressAreaCode = callingNumber.substring(0, 4);
        answerAddressAreaCode = answerNumber.substring(0, 4);
    }
/*    //座机打手机 1
    public CallRecord(String callingNumber, String answerNumber, String answerAddressAreaCode, Date startTime, Date endTime) {
        super(callingNumber, answerNumber);
        this.startTime = startTime;
        this.endTime = endTime;
        callingAddressAreaCode = callingNumber.substring(0, 4);
        this.answerAddressAreaCode = answerAddressAreaCode;
    }

    //手机打座机 2
    public CallRecord(String callingNumber, String callingAddressAreaCode, String answerNumber, Date startTime, Date endTime) {
        super(callingNumber, answerNumber);
        this.startTime = startTime;
        this.endTime = endTime;
        this.callingAddressAreaCode = callingAddressAreaCode;
    }*/

    public CallRecord(String callingNumber, String callingAreaCode_Or_AnsNumber, String ansNumber_Or_AnsAreaCode, Date startTime, Date endTime, int mod) {
        if (mod == 1) {
            this.callingNumber = callingNumber;
            this.answerNumber = callingAreaCode_Or_AnsNumber;
            this.startTime = startTime;
            this.endTime = endTime;
            callingAddressAreaCode = callingNumber.substring(0, 4);
            answerAddressAreaCode = ansNumber_Or_AnsAreaCode;
        } else {
            this.callingNumber = callingNumber;
            this.answerNumber = ansNumber_Or_AnsAreaCode;
            this.startTime = startTime;
            this.endTime = endTime;
            callingAddressAreaCode = callingAreaCode_Or_AnsNumber;
            answerAddressAreaCode = ansNumber_Or_AnsAreaCode.substring(0, 4);
        }
    }

    //手机互打
    public CallRecord(String callingNumber, String callingAddressAreaCode, String answerNumber, String answerAddressAreaCode, Date startTime, Date endTime) {
        super(callingNumber, answerNumber);
        this.callingAddressAreaCode = callingAddressAreaCode;
        this.answerAddressAreaCode = answerAddressAreaCode;
        this.startTime = startTime;
        this.endTime = endTime;
    }

    /*南昌市内拨打*/
    public boolean callInCity() {
        return "0791".equals(callingAddressAreaCode);
    }

    /*非市内的省内拨打*/
    public boolean callInProvince() {
        if (callInCity() || callingAddressAreaCode.length() < 3) return false;
        if ("0701".equals(callingAddressAreaCode)) return true;
        return "079".equals(callingAddressAreaCode.substring(0, 3)) && (callingAddressAreaCode.charAt(3) >= '0' && callingAddressAreaCode.charAt(3) <= '9');
    }

    /*非省内拨打*/
    public boolean callInLand() {
        return !callInProvince();
    }

    /*南昌市内接听*/
    public boolean ansInCity() {
        return "0791".equals(answerAddressAreaCode);
    }

    /*非市内的省内接听*/
    public boolean ansInProvince() {
        if (ansInCity() || answerAddressAreaCode.length() < 3) return false;
        if ("0701".equals(answerAddressAreaCode)) return true;
        return "079".equals(answerAddressAreaCode.substring(0, 3)) && (answerAddressAreaCode.charAt(3) >= '0' && answerAddressAreaCode.charAt(3) <= '9');
    }

    /*非省内接听*/
    public boolean ansInLand() {
        return !ansInProvince();
    }


    public String getCallingAddressAreaCode() {
        return callingAddressAreaCode;
    }

    public String getAnswerAddressAreaCode() {
        return answerAddressAreaCode;
    }

    public int getSecMinus() {
        return (int) ((endTime.getTime() - startTime.getTime()) / 1000);
    }
}

/*
 * CallChargeRule 电话计费
 * 针对电话的不同的使用终端有不同的计费规则*/
abstract class CallChargeRule extends ChargeRule {
    public abstract double calCost(UserRecords userRecords);

    public boolean InCity(String callingAddressAreaCode) {
        return "0791".equals(callingAddressAreaCode);
    }

    public boolean InProvince(String callingAddressAreaCode) {
        if (InCity(callingAddressAreaCode) || callingAddressAreaCode.length() < 3) return false;
        if ("0701".equals(callingAddressAreaCode)) return true;
        return "079".equals(callingAddressAreaCode.substring(0, 3)) && (callingAddressAreaCode.charAt(3) >= '0' && callingAddressAreaCode.charAt(3) <= '9');
    }

    public boolean InLand(String callingAddressAreaCode) {
        if (InCity(callingAddressAreaCode)) return false;
        return !InProvince(callingAddressAreaCode);
    }
}


abstract class MessageChargeRule extends ChargeRule {
    public abstract double calCost(UserRecords userRecords);
}

class SendMessageRule extends MessageChargeRule {
    @Override
    public double calCost(UserRecords userRecords) {
        int num = 0;
        for (MessageRecord m : userRecords.getSendMessageRecords()) num += getMessageNum(m);
        if (num > 5) return 0.7 + (num - 5) * 0.3;
        else if (num > 3) return 0.3 + (num - 3) * 0.2;
        else return num * 0.1;
    }

    private int getMessageNum(MessageRecord messageRecord) {
        int len = messageRecord.getMessage().length();
        int res = len / 10 ;
        res += len % 10 != 0 ? 1 : 0;
        return res;
    }
}

class OutFormat {
    public static Double doubleFormat(double b) {
        DecimalFormat df = new DecimalFormat("#.00");
        return Double.valueOf(df.format(b));
    }
}

代码类图

X6nhHe.png

分析

个人的思路是将用户和记录读入后,分别存于容器,再将数据传到一个DataCenter的类,此类的职责是将所有通讯记录匹配到用户
之后在用户得到所有自己的通讯记录后,将其分类存于不同的容器,从而让不同的Rule处理自己应处理的数据,分别计算费用并汇总;

其实还有比较简单的思路,那就是将用户和记录分别存于容器,遍历每个用户,让每个用户遍历所有通讯记录,找到自己的通讯记录并将其按类型计费汇总,很明显,这样写出的代码性能会很差,所以没有采用这样的思路;

踩坑心得

关于HashSet的使用

疑惑代码:

import java.util.HashSet;

public class Main {
   public static void main(String[] args) {
       HashSet<User> users = new HashSet<>();
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       for(User u : users) System.out.println(u);
   }
}
class User{
   String number;
   //*********************************************************************************//
   public User(String number) {
       this.number = number;
   }
}
输出:
User@5594a1b5
User@3b6eb2ec
User@3ac3fd8b
User@6a5fc7f7
User@1e643faf
   
进程已结束,退出代码0

很明显,他们虽然放到了HashSet中,但是HashSet并不认为他们是同一对象

User重写了hashCode()

import java.util.HashSet;

public class Main {
   public static void main(String[] args) {
       HashSet<User> users = new HashSet<>();
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       for(User u : users) System.out.println(u);
   }
}
class User{
   String number;
   public User(String number) {
       this.number = number;
   }

   @Override
   public int hashCode() {
       return Integer.parseInt(number);
   }
}
输出
User@756b5b3
User@756b5b3
User@756b5b3
User@756b5b3
User@756b5b3
   
进程已结束,退出代码0

虽然他们的地址是一样的,但是HashSet仍不觉的这是同一对象

User重写了equals()

import java.util.HashSet;

public class Main {
   public static void main(String[] args) {
       HashSet<User> users = new HashSet<>();
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       users.add(new User("123123123"));
       for(User u : users) System.out.println(u);
   }
}
class User{
   String number;
   public User(String number) {
       this.number = number;
   }

   @Override
   public int hashCode() {
       return Integer.parseInt(number);
   }

   @Override
   public boolean equals(Object obj) {
       return number.equals(((User)obj).number);
   }
}
输出
User@756b5b3
   
进程已结束,退出代码0

成功对User去重

改进建议

重载构造函数类型冲突

//座机打手机 1
public CallRecord(String callingNumber,
                 String answerNumber, String answerAddressAreaCode,
                 Date startTime, Date endTime) {
   super(callingNumber, answerNumber);
   this.startTime = startTime;
   this.endTime = endTime;
   callingAddressAreaCode = callingNumber.substring(0, 4);
   this.answerAddressAreaCode = answerAddressAreaCode;
}

//手机打座机 2
public CallRecord(String callingNumber, String callingAddressAreaCode,
                 String answerNumber,
                 Date startTime, Date endTime) {
   super(callingNumber, answerNumber);
   this.startTime = startTime;
   this.endTime = endTime;
   this.callingAddressAreaCode = callingAddressAreaCode;
}

解决方案1:

public CallRecord(String callingNumber,
                 String callingAreaCode_Or_AnsNumber,
                 String ansNumber_Or_AnsAreaCode,
                 Date startTime, Date endTime,
                 int mod) {
   if (mod == 1) {
       this.callingNumber = callingNumber;
       this.answerNumber = callingAreaCode_Or_AnsNumber;
       this.startTime = startTime;
       this.endTime = endTime;
       callingAddressAreaCode = callingNumber.substring(0, 4);
       answerAddressAreaCode = ansNumber_Or_AnsAreaCode;
   } else {
       this.callingNumber = callingNumber;
       this.answerNumber = ansNumber_Or_AnsAreaCode;
       this.startTime = startTime;
       this.endTime = endTime;
       callingAddressAreaCode = callingAreaCode_Or_AnsNumber;
       answerAddressAreaCode = ansNumber_Or_AnsAreaCode.substring(0, 4);
   }
}

利用一个mod来判断使用哪个重载

解决方案2:

class CallRecord{
	//*********************************************************************************//
   public CallRecord(Number callingNumber, Number answerNumber, Date startTime, Date endTime) {
       super(callingNumber, answerNumber);
       this.startTime = startTime;
       this.endTime = endTime;
   }
	//*********************************************************************************//
}
class Number{
   String number,addressNumber;
   public Number(String number, String addressNumber) {
       this.number = number;
       this.addressNumber = addressNumber;
   }
}

用一个Number类来根治类型冲突的问题,思路也更清晰

总结

通过这几周的作业,克服了对正则表达式的恐惧,对程序的设计有了更开阔的思维,学会了用java.text.SimpleDateFormat格式化日期、用java.util.Date存储日期、还学会了用HashSet<>容器存储对象、以及用Collections.sort()对容器中实现Compareable<>接口的类的对象进行排序.....

posted @ 2022-06-10 15:33  Pseach  阅读(81)  评论(0)    收藏  举报