3

I'm an old-time programmer from the 80s proficient with C and Pascal. I'm pretty new to Java and its concept. In trying to learn the new ways of Java using OOP techniques I'm rather confused about the right way of putting an application together.

I'm trying to build a basic program with the following rules.

An organisation has its own in-house library. The Staff class is general and has Name and Phone. Some of the employees is a librarian. The others are members. So Member and Librarian are specialised classes. I presume we call them inherited or extended in this context.

Now I'm trying to build basic functionality like input and print a member record. I'm trying to build a text-based menu. Perhaps later I'll consider sub-menus. For now it's just a simple menu.

I don't know if I should make the menu an object as well but that's what I think I'll do.

With this in mind, here's what I've done.

My main program:

public class Library extends Menus {
    public static void main(String[] args) {
        Menus Start = new Menus();
        Start.ShowMainMenu();

    }
}

StaffClass.java

public class StaffClass {
    private String Name;
    private String Phone;

    public void InputData() {
        Scanner UserInput = new Scanner(System.in);

        System.out.print("Enter staff name "); Name = UserInput.nextLine();
        System.out.print("Enter staff phone number "); Phone = UserInput.nextLine();

    }

    public void PrintData() {
        System.out.println("Name : " + Name);
        System.out.println("Phone : " + Phone);

    }
}//end StaffClass

Menus.java

public class Menus extends MemberClass {

    int c;
    public void ShowMainMenu() {
        Scanner ui = new Scanner(System.in);
        while(1==1) {
            System.out.println("Main menu");
            System.out.println("1. Add student");
            System.out.println("2. Display all");
            System.out.println("3. exit");
            System.out.print("Enter choice"); c = ui.nextInt();

            switch(c) {
                case 1 : getInputs(); /*System.out.println("option 1");*/ break;
                case 2 : ShowAllInfo(); break;
                case 3 : System.out.println("Leaving the program now..."); System.exit(0); break;
                default  : System.out.println("error.");
            }

        }

    }

}

MemberClass.java

public class MemberClass extends StaffClass {
    int TotalBooks;
    public void getInputs() {
        InputData();
        UpdateTotalBooks();
    }

    public void ShowAllInfo() {
        PrintData();
        System.out.println("total books taken = " + TotalBooks);
    }

    public void UpdateTotalBooks() {
        Scanner ui = new Scanner(System.in);

        System.out.print("Enter number of books "); TotalBooks = ui.nextInt();        

    }

}

It's the first Java program that I've put together with so many classes in it + a menu system.

My key question is if this is the correct way of assembling a program in Java or is there another way.

Please feel free to suggest the best options/changes to the code. But I'd like to keep the concept of generalisation and specialisation.

Thanks!

4

2 回答 2

4

您正在过度使用类——类旨在表示数据类型,或者是静态方法(本质上只是函数)的持有者。但是,您正在使用类作为分发函数的一种方式,然后应用虚假继承。此外,您从同一个类继承Menus 实例Menus化——这没有任何意义。

换句话说,您不需要仅仅为了它而使用继承和很多类。除了许多不称职的开发人员过度使用强制或建议过度使用类和继承的类之外,Java 中没有任何东西。

函数,最好是没有副作用/全局状态的函数,容易推理和正确。而分散在父类链中的复杂状态变量是解决大问题的捷径。

我会使用一些简单的东西,例如:

public class Library {
    public static void main(final String[] args) {
        showMainMenu();
    }

    int totalBooks;

    public static void showMainMenu() {
        final Scanner ui = new Scanner(System.in);
        while (true) {
            System.out.println("Main menu");
            System.out.println("1. Add student");
            System.out.println("2. Display all");
            System.out.println("3. exit");
            System.out.print("Enter choice");

            switch (ui.nextInt()) {
                case 1:
                    getInputs();
                    /*System.out.println("option 1");*/
                    break;
                case 2:
                    showAllInfo();
                    break;
                case 3:
                    System.out.println("Leaving the program now...");
                    System.exit(0);
                    break;
                default:
                    System.out.println("error.");
            }
        }
    }

    public static void getInputs() {
        inputData();
        updateTotalBooks();
    }

    public static void showAllInfo() {
        printData();
        System.out.println("total books taken = " + totalBooks);
    }

    public static void updateTotalBooks() {
        System.out.print("Enter number of books ");
        totalBooks = new Scanner(System.in).nextInt();
    }
}

如果您需要将其拆分为不同的模块,请不要使用继承。相反,创建一个StateDatabase类之类的东西,并在静态函数之间传递它,这些函数要么修改传入的数据,要么,如果你想窥探函数式编程和不可变数据结构的世界,返回数据的更改副本:

class State {
  // make these non-final if you want State to be mutable
  // (I'm too lazy to generate getters; and in Scala you don't have to)
  public final int totalBooks = 0;
  public final String someOtherState = "hello";

  public State(final int totalBooks, final String someOtherState) {
    this.totalBooks = totalBooks;
    this.someOtherState = someOtherState;
  }

  public State withTotalBooks(final int newValue) {
    return new State(newValue, someOtherState);
  }
  public State withSomeOtherState(final int newValue) {
    return new State(totalBooks, newValue);
  }
}

class App {
  public static void main(final String[] args) {
    State state = new State();
    // at the top-most level of the program, it's OK to use global state
    state = BookManager.updateNumBooks(state)
  }
}

class BookManager {
  public static State updateNumBooks(final State state) {
    return state.withTotalNumBooks(123);
  }

  // or, if State is mutable:
  public static void updateNumBooks(final State state) {
    // UI code here
    state.totalNumBooks = 123;
  }      
}

class HelloModule {
  public static State updateMsg(final State state) {
    // UI code
    return state.withSomeOtherState("hello world");
  }

  // or, if State is mutable:
  public static void updateMsg(final State state) {
    // UI code
    state.someOtherState = "hello world";
  }
}

// etc

并且,作为最后的评论:所有这些在简洁的函数式编程 JVM 语言中看起来会更好,比如Scala(甚至是Frege)。如果您必须继续使用 Java,请至少阅读有关函数式编程的内容以及如何在设计程序的方式中从中受益:

于 2014-11-14T16:15:34.750 回答
3

太长的评论,但不是答案。

  1. 会有课。希望他们中的许多人。
  2. 应遵循 Java 命名约定,例如,以小写字母开头的命名方法。
  3. StaffClass是一个糟糕的名字,而只是使用Staff.
  4. 考虑以不同的方式为其提供输入:按原样,Staff只能由其自己的输入法填充。但是数据如何进入Staff实例应该与 a 的Staff实际情况完全无关。
  5. 没有“一种正确的方法”来从类中组装 Java 程序,甚至没有一种正确的方法来分解职责。但是单一职责原则很重要。同样重要的是方法(可能还有类)应该始终在相同的抽象级别上运行的概念。
于 2014-11-14T16:03:46.950 回答