All about abstract classes

本文详细介绍了C#中抽象类的概念及使用方法,包括抽象方法、属性的实现方式,以及抽象类与接口的区别。通过实例展示了如何定义和继承抽象类。

http://www.codeproject.com/Articles/6118/All-about-abstract-classes


Introduction

Abstract classes are one of the essential behaviors provided by .NET. Commonly, you would like to make classes that only represent base classes, and don’t want anyone to create objects of these class types. You can make use of abstract classes to implement such functionality in C# using the modifier 'abstract'.

An abstract class means that, no object of this class can be instantiated, but can make derivations of this.

An example of an abstract class declaration is:

abstract class absClass
{
}

An abstract class can contain either abstract methods or non abstract methods. Abstract members do not have any implementation in the abstract class, but the same has to be provided in its derived class.

An example of an abstract method:

abstract class absClass
{
  public abstract void abstractMethod();
}

Also, note that an abstract class does not mean that it should contain abstract members. Even we can have an abstract class only with non abstract members. For example:

abstract class absClass
{
    public void NonAbstractMethod()
    {
        Console.WriteLine("NonAbstract Method");
    }
}

A sample program that explains abstract classes:

using System;

namespace abstractSample
{
      //Creating an Abstract Class
      abstract class absClass
      {
            //A Non abstract method
            public int AddTwoNumbers(int Num1, int Num2)
            {
                return Num1 + Num2;
            }

            //An abstract method, to be
            //overridden in derived class
            public abstract int MultiplyTwoNumbers(int Num1, int Num2);
      }

      //A Child Class of absClass
      class absDerived:absClass
      {
            [STAThread]
            static void Main(string[] args)
            {
               //You can create an
               //instance of the derived class

               absDerived calculate = new absDerived();
               int added = calculate.AddTwoNumbers(10,20);
               int multiplied = calculate.MultiplyTwoNumbers(10,20);
               Console.WriteLine("Added : {0}, 
                       Multiplied : {1}", added, multiplied);
            }

            //using override keyword,
            //implementing the abstract method
            //MultiplyTwoNumbers
            public override int MultiplyTwoNumbers(int Num1, int Num2)
            {
                return Num1 * Num2;
            }
      }
}

In the above sample, you can see that the abstract class absClass contains two methods AddTwoNumbers and MultiplyTwoNumbers. AddTwoNumbers is a non-abstract method which contains implementation and MultiplyTwoNumbers is an abstract method that does not contain implementation.

The class absDerived is derived from absClass and the MultiplyTwoNumbers is implemented on absDerived. Within the Main, an instance (calculate) of the absDerived is created, and calls AddTwoNumbers and MultiplyTwoNumbers. You can derive an abstract class from another abstract class. In that case, in the child class it is optional to make the implementation of the abstract methods of the parent class.

Example

//Abstract Class1
abstract class absClass1
{
    public abstract int AddTwoNumbers(int Num1, int Num2);
    public abstract int MultiplyTwoNumbers(int Num1, int Num2);
}

//Abstract Class2
abstract class absClass2:absClass1
{
    //Implementing AddTwoNumbers
    public override int AddTwoNumbers(int Num1, int Num2)
    {
        return Num1+Num2;
    }
}

//Derived class from absClass2
class absDerived:absClass2
{
    //Implementing MultiplyTwoNumbers
    public override int MultiplyTwoNumbers(int Num1, int Num2)
    {
        return Num1*Num2;
    }
}

In the above example, absClass1 contains two abstract methods AddTwoNumbers and MultiplyTwoNumbers. The AddTwoNumbers is implemented in the derived class absClass2. The class absDerived is derived from absClass2 and the MultiplyTwoNumbers is implemented there.

Abstract properties

Following is an example of implementing abstract properties in a class.

//Abstract Class with abstract properties
abstract class absClass
{
    protected int myNumber;
    public abstract int numbers
    {
        get;
        set;
    }
}

class absDerived:absClass
{
    //Implementing abstract properties
    public override int numbers
    {
        get
        {
            return myNumber;
        }
        set
        {
            myNumber = value;
        }
    }
}

In the above example, there is a protected member declared in the abstract class. The get/set properties for the member variable myNumber is defined in the derived class absDerived.

Important rules applied to abstract classes

An abstract class cannot be a sealed class. I.e. the following declaration is incorrect.

//Incorrect
abstract sealed class absClass
{
}

Declaration of abstract methods are only allowed in abstract classes.

An abstract method cannot be private.

//Incorrect
private abstract int MultiplyTwoNumbers();

The access modifier of the abstract method should be same in both the abstract class and its derived class. If you declare an abstract method as protected, it should be protected in its derived class. Otherwise, the compiler will raise an error.

An abstract method cannot have the modifier virtual. Because an abstract method is implicitly virtual.

//Incorrect
public abstract virtual int MultiplyTwoNumbers();

An abstract member cannot be static.

//Incorrect
publpublic abstract static int MultiplyTwoNumbers();

Abstract class vs. Interface

An abstract class can have abstract members as well non abstract members. But in an interface all the members are implicitly abstract and all the members of the interface must override to its derived class.

An example of interface:

interface iSampleInterface
{
  //All methods are automaticall abstract
  int AddNumbers(int Num1, int Num2);
  int MultiplyNumbers(int Num1, int Num2);
}

Defining an abstract class with abstract members has the same effect to defining an interface.

The members of the interface are public with no implementation. Abstract classes can have protected parts, static methods, etc.

A class can inherit one or more interfaces, but only one abstract class.

Abstract classes can add more functionality without destroying the child classes that were using the old version. In an interface, creation of additional functions will have an effect on its child classes, due to the necessary implementation of interface methods to classes.

The selection of interface or abstract class depends on the need and design of your project. You can make an abstract class, interface or combination of both depending on your needs.


You are asked to design and implement a Python-based system for managing a small library. The system should support the following core tasks, including manage users of different types (students, staff, and other members), manage the collection of books in the library and track and update loan records for borrowed books. Description The library has provided you with three CSV files containing its current data in the data folder: users.csv for user information, books.csv for book information and loans.csv containing loan history. In Task 1-3, you can assume all CSV files contain valid data. You are allowed to modify the import statements in the scaffold or move the import statements to different modules if required; but you are not allowed to import any modules which weren't originally imported in the scaffold. Users (users.csv) This file contains details of all registered users: Fields: user ID, password, name, role, and department (for students and staff only). User types: Student (s prefix in the user ID) Staff (e prefix in the user ID) Others (o prefix in the user ID) Each user type follows specific borrowing policies: Users Physical book Online Quota Student 10 days Unlimited 4 Staff 14 days Unlimited 6 Other 7 days Unlimited 2 Users Student Staff Other ​ Physical book 10 days 14 days 7 days ​ Online Unlimited Unlimited Unlimited ​ Quota 4 6 2 ​ ​ All users can borrow, return, and renew books, as well as view their active loans and loan policies. Only staff can add, update, or view detailed information about users and books. (More detail in Task 2-3). Books (books.csv) This file contains information about books in the collection: Fields: book ID, type (e.g., physical or online), total copies, title, authors, year, and keywords (colon-separated). Each book has a unique ID beginning with a character that denotes its category, followed by 4 digits. Physical books are identified by the prefix P in the Book ID. Online books (e-book) are identified by the prefix E in the Book ID. For online books, the total copies field is always 0. Loans (loans.csv) This file contains borrowing records: Fields: user ID, book ID, borrow date, due date, returned date. All dates are in the following format dd/mm/yyyy. The due date is automatically calculated based on loan policy. Active loans are those without a returned date. Your Task Write a program that reads users, books and loans from files users.csv, books.csv and loans.csv and a simple menu that allow interaction with the data. You are provided with 3 modules: user.py, book.py and task1.py. Your task is to Complete the implementation User and Book class in the users.py and books.py modules. You are allowed to add additional classes and functions if necessary. Implement the interaction menu in task1.py Login Menu When the program starts, the user is prompted to log in with their ID and password. If the user id does not exist or user id and password does not match, the program will print "Invalid credentials. x attempt(s) remaining." and prompt user to login again. Successful login displays a welcome message with the user's name and role. Users have three login attempts before the program prints a message "Sorry you're out of attempts. Please contact your librarian for assistance." and back to welcome and login menu. In the login menu, user can type "quit" to terminate the program. Welcome to Library Login as: s31267 Password: chr1267 Logged in as Chris Manner (Student) Main menu Once logged in, users see a personalized main menu based on their role. For student, other users, and staff members outside the Library department: Logged in as Chris Manner (Student) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: For staff from the Library department: Logged in as Mary Alan (Staff) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Library Report ================================== Enter your choice: A user's input may provide incorrect choice, e.g. 5 or four. In this case your program should prompt for input again. 0. Quit The program will print the message: "Goodbye!", and terminates. 1. Log out The user is logged out and returned to the welcome screen and login menu. 2. View account policies Upon entering 2, the program will display user current membership policies, and their total loans. Logged in as Chris Manner (Student) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 2 Student Chris Manner. Policies: maximum of 10 days, 4 items. Current loans: 2 (1 physical / 1 online). 3. View my loans Upon entering 3, the program will display all active loans (sorted by due date). Active loans are those without a returned date. Logged in as Chris Manner (Student) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 3 You are currently have 2 loan(s). 1. P0006 'Hands-On ML' by Aurelien Geron (2019). Due date: 13/09/2025. 2. E0001 'Python Crash Course' by Eric Matthes (2015). Due date: 15/09/2025. 4. Library Report (Library Staff only) Upon entering 4, library staff can access a summary report of the library. This report provides key statistics, including the total number of users (with a breakdown by role), as well as details about the book collection and available books which currently have one or more copies available. Logged in as Mary Alan (Staff) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Library Report ================================== Enter your choice: 4 Library Report - 9 users, including 4 student(s), 3 staff and 2 others. - 14 books, including 10 physical book(s) (7 currently available) and 4 online book(s). Examples User inputs are in bold font below. Example 1 Welcome to Library Login as: s312 Password: chr1267 Invalid credentials. 2 attempt(s) remaining. Login as: s31267 Password: chr12 Invalid credentials. 1 attempt(s) remaining. Login as: s31267 Password: chr126 Sorry you're out of attempts. Please contact your librarian for assistance. Welcome to Library Login as: quit Goodbye! Example 2 Welcome to Library Login as: s31267 Password: chr1267 Logged in as Chris Manner (Student) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 2 Student Chris Manner. Policies: maximum of 10 days, 4 items. Current loans: 2 (1 physical / 1 online). ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 3 You are currently have 2 loan(s). 1. P0006 'Hands-On ML' by Aurelien Geron (2019). Due date: 13/09/2025. 2. E0001 'Python Crash Course' by Eric Matthes (2015). Due date: 15/09/2025. ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 0 Goodbye! Example 3 Welcome to Library Login as: e118102 Password: pa55word Logged in as Mary Alan (Staff) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Library Report ================================== Enter your choice: 4 Library report - 9 users, including 4 student(s), 3 staff, and 2 others. - 14 books, including 10 physical book(s) (7 currently available) and 4 online book(s). ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Library Report ================================== Enter your choice: 5 Enter your choice: 3 You are currently have 1 loan(s). 1. P0004 'The Hitchhiker's Guide to the Galaxy' by Douglas Adams (1985). Due date: 17/09/2025. ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans 4. Library Report ================================== Enter your choice: 0 Goodbye! Example 4 Welcome to Library Login as: o56789 Password: hackme Logged in as Chloe (Others) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 2 Others Chloe. Policies: maximum of 7 days, 2 items. Current loans: 0 (0 physical / 0 online). ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 3 You are currently have 0 loan(s). ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 0 Goodbye! Example 5 Login as: e45261 Password: readmore Logged in as Lan Nguyen (Staff) ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 2 Staff Lan Nguyen. Policies: maximum of 14 days, 6 items. Current loans: 1 (1 physical / 0 online). ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 3 You are currently have 1 loan(s). 1. P0019 'Principles of Marketing' by Philip Kotler (2016). Due date: 21/09/2025. ================================== My Library Account 0. Quit 1. Log out 2. View account policies 3. View my loans ================================== Enter your choice: 0 Goodbye!from abc import ABC, abstractmethod import csv import datetime import re class User(ABC): # Your code goes here passimport csv import datetime import re class Book: # your code goes hereimport user import book import csv import datetime import typing def main(user_file: str, book_file:str, loan_file:str) -> None: """ This is the entry of your program. Please DO NOT modify this function signature, i.e. function name, parameters Parameteres: - user_file (str): path the `users.csv` which stores user information - book_file (str): path the `books.csv` which stores book information - loan_file (str): path the `loans.csv` which stores loan information """ # Your implemetation goes here pass if __name__ == "__main__": main('data/users.csv', 'data/books.csv', 'data/loans.csv')
10-11
代码概述 本程序是一个基于Python的图书馆管理系统,支持用户登录、查看个人借阅政策、查看当前借阅记录以及图书馆员生成报告等功能。系统通过读取`users.csv`、`books.csv`和`loans.csv`三个文件加载数据,并根据用户角色展示不同的菜单选项。 代码解析 ```python # user.py from abc import ABC, abstractmethod import csv import datetime import re class User(ABC): def __init__(self, user_id: str, password: str, name: str, role: str, department: str = None): self.user_id = user_id self.password = password self.name = name self.role = role self.department = department self.loans = [] @abstractmethod def get_loan_policy(self): pass def is_library_staff(self) -> bool: return self.role == "Staff" and self.department == "Library" def add_loan(self, loan): self.loans.append(loan) def get_active_loans(self): return [loan for loan in self.loans if loan.returned_date is None] def get_physical_online_count(self): physical = sum(1 for loan in self.get_active_loans() if loan.book.type == "physical") online = len(self.get_active_loans()) - physical return physical, online def __str__(self): return f"{self.name} ({self.role})" ``` ```python # book.py import csv import datetime import re class Book: def __init__(self, book_id: str, book_type: str, total_copies: int, title: str, authors: str, year: int, keywords: str): self.book_id = book_id self.type = book_type self.total_copies = total_copies self.title = title self.authors = authors self.year = year self.keywords = keywords.split(':') if keywords else [] def is_available(self) -> bool: if self.type == "online": return True borrowed_count = sum(1 for loan in self.loans if loan.returned_date is None) return borrowed_count < self.total_copies def __str__(self): return f"{self.title} by {self.authors} ({self.year})" ``` ```python # task1.py import user import book import csv import datetime import typing def parse_date(date_str: str) -> typing.Optional[datetime.date]: if not date_str: return None day, month, year = map(int, date_str.split('/')) return datetime.date(year, month, day) def load_users(file_path: str) -> dict: users = {} with open(file_path, newline='', encoding='utf-8') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: user_id, pwd, name, role, dept = row if user_id.startswith('s'): u = user.Student(user_id, pwd, name, role, None) elif user_id.startswith('e'): u = user.Staff(user_id, pwd, name, role, dept) else: u = user.Other(user_id, pwd, name, role, None) users[user_id] = u return users def load_books(file_path: str) -> dict: books = {} with open(file_path, newline='', encoding='utf-8') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: book_id, btype, copies, title, authors, year, keywords = row b = book.Book(book_id, btype, int(copies), title, authors, int(year), keywords) books[book_id] = b b.loans = [] return books def load_loans(file_path: str, users: dict, books: dict): loans = [] with open(file_path, newline='', encoding='utf-8') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: user_id, book_id, borrow_date, due_date, returned_date = row if user_id in users and book_id in books: loan = Loan(users[user_id], books[book_id], borrow_date, due_date, returned_date) users[user_id].add_loan(loan) books[book_id].loans.append(loan) loans.append(loan) return loans class Loan: def __init__(self, user, book, borrow_str, due_str, return_str): self.user = user self.book = book self.borrow_date = parse_date(borrow_str) self.due_date = parse_date(due_str) self.returned_date = parse_date(return_str) def main(user_file: str, book_file: str, loan_file: str) -> None: users = load_users(user_file) books = load_books(book_file) load_loans(loan_file, users, books) while True: print("Welcome to Library") user_input = input("Login as: ").strip() if user_input == "quit": print("Goodbye!") break if user_input not in users: print("Invalid credentials. 2 attempt(s) remaining.") user_input = input("Login as: ").strip() if user_input not in users: print("Invalid credentials. 1 attempt(s) remaining.") user_input = input("Login as: ").strip() if user_input not in users: print("Sorry you're out of attempts. Please contact your librarian for assistance.") continue pwd = input("Password: ").strip() if users[user_input].password != pwd: print("Sorry you're out of attempts. Please contact your librarian for assistance.") continue else: pwd = input("Password: ").strip() if users[user_input].password != pwd: print("Invalid credentials. 1 attempt(s) remaining.") pwd = input("Password: ").strip() if users[user_input].password != pwd: print("Sorry you're out of attempts. Please contact your librarian for assistance.") continue else: pwd = input("Password: ").strip() if users[user_input].password != pwd: print("Invalid credentials. 2 attempt(s) remaining.") pwd = input("Password: ").strip() if users[user_input].password != pwd: print("Invalid credentials. 1 attempt(s) remaining.") pwd = input("Password: ").strip() if users[user_input].password != pwd: print("Sorry you're out of attempts. Please contact your librarian for assistance.") continue current_user = users[user_input] print(f"Logged in as {current_user.name} ({current_user.role})") while True: menu = [ "My Library Account", "0. Quit", "1. Log out", "2. View account policies", "3. View my loans" ] if current_user.is_library_staff(): menu.append("4. Library Report") print("=" * 40) for item in menu: print(item) print("=" * 40) try: choice = input("Enter your choice: ").strip() if not choice.isdigit(): continue choice = int(choice) except: continue if choice == 0: print("Goodbye!") return elif choice == 1: break elif choice == 2: policy = current_user.get_loan_policy() active_loans = current_user.get_active_loans() num_loans = len(active_loans) phys, online = current_user.get_physical_online_count() print(f"{current_user.role} {current_user.name}. Policies: maximum of {policy['days']} days, {policy['quota']} items. Current loans: {num_loans} ({phys} physical / {online} online).") elif choice == 3: active_loans = sorted(current_user.get_active_loans(), key=lambda x: x.due_date) count = len(active_loans) print(f"You are currently have {count} loan(s).") for i, loan in enumerate(active_loans, 1): print(f"{i}. {loan.book.book_id} '{loan.book.title}' by {loan.book.authors} ({loan.book.year}). Due date: {loan.due_date.strftime('%d/%m/%Y')}.") elif choice == 4 and current_user.is_library_staff(): total_users = len(users) students = sum(1 for u in users.values() if u.user_id.startswith('s')) staffs = sum(1 for u in users.values() if u.user_id.startswith('e')) others = sum(1 for u in users.values() if u.user_id.startswith('o')) total_books = len(books) physical_books = sum(1 for b in books.values() if b.type == "physical") available_physical = sum(1 for b in books.values() if b.type == "physical" and b.is_available()) online_books = sum(1 for b in books.values() if b.type == "online") print("Library Report") print(f"- {total_users} users, including {students} student(s), {staffs} staff, and {others} others.") print(f"- {total_books} books, including {physical_books} physical book(s) ({available_physical} currently available) and {online_books} online book(s).") else: continue # Extend User subclasses class Student(user.User): def get_loan_policy(self): return {"days": 10, "quota": 4} class Staff(user.User): def get_loan_policy(self): return {"days": 14, "quota": 6} class Other(user.User): def get_loan_policy(self): return {"days": 7, "quota": 2} ``` 知识点 - **抽象基类(ABC)与继承**:使用`abc.ABC`和`@abstractmethod`定义抽象类`User`,确保子类实现`get_loan_policy`方法。 - **CSV文件读取与数据建模**:利用`csv`模块解析CSV文件,将每行数据映射为对象实例,构建用户、书籍和借阅关系模型。 - **日期处理与字符串格式化**:通过`datetime.date`解析日期字符串,并使用`.strftime()`输出指定格式的日期信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值