目錄
對於初學者來說很多不知道抽象類和接口類是怎麼選擇。 本章做一下簡單的講解
總的來說:接口類是制定標準、抽象類可以作爲模板
一、什麼是抽象類
我們知道類是對物事的抽象,這樣它的範圍可以適合這一類的事物。爲了讓它適應的範圍更廣,能不能對類再進行一次抽象呢?是可以的,那就是抽象類,對類進行二次抽象。
抽象類常見的就是模板設計,就像現實中的各種模板,只有模板填寫之後纔會有意義。
比如我們寫一個車的類,再對它進行抽象呢?那就是交通工具了,它是不是包括得更廣了?反過來,交通工具類à車類,那車類也不是實物,也是一個抽象,不是一個實現,實例化指的是實例,所以抽象類不能直接實例化!
簡單來說抽象類就是:抽象的抽象!
二、抽象類的應用場景及例子
2.1 應用場景
a、在某些情況下,某個父類只是知道其子類應該包含怎樣的方法,但無法準確知道這些子類如何實現這些方法。
b.從多個具有相同特徵的類中抽象出一個抽象類,以這個抽象類作爲子類的模板,從而避免了子類設計的隨意性。
2.2 抽象類的例子
我們以登錄爲例子,我們知道一般電商登錄會可以使用用戶名、密碼、郵箱3種登錄方式,前提這些都是唯一的不能重複。
如下圖所示:
我們現在用java命令的方式實現這3種功能,這3種方法基本是一樣的,只是裏面的實現邏輯有所差別,所以我們可以把它抽象成一個模板,每種登錄方式重寫即可。
因爲模板登錄頁肯定有主題(css樣式、js、html等之類)我們打包成一套主題即可,爲了簡單些我再添加一個主題。
2.2.1 目錄結構
AccountValidatorUtil:正則表達式判斷輸入的是手機、郵件、還是用戶名
Login:登錄抽象類,主要是做模板作用
LoginByEmail:實現郵箱登陸功能
LoginByTel:實現電話登陸功能
LoginByUsername:實現用戶名登錄功能
LoginMain:主程序
2.2.2 實現代碼
com.hualinux.login.AccountValidatorUtil.java代碼如下:
package com.hualinux.login;
import java.util.regex.Pattern;
public class AccountValidatorUtil {
/**
* 正則表達式:驗證用戶名
*/
public static final String REGEX_USERNAME = "^[a-zA-Z]\\w{5,20}$";
/**
* 正則表達式:驗證密碼
*/
public static final String REGEX_PASSWORD = "^[a-zA-Z0-9]{6,20}$";
/**
* 正則表達式:驗證手機號
*/
public static final String REGEX_MOBILE = "^((17[0-9])|(14[0-9])|(13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
/**
* 正則表達式:驗證郵箱
*/
public static final String REGEX_EMAIL = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
/**
* 校驗用戶名
*
* @param username
* @return 校驗通過返回true,否則返回false
*/
public static boolean isUsername(String username) {
return Pattern.matches(REGEX_USERNAME, username);
}
/**
* 校驗密碼
*
* @param password
* @return 校驗通過返回true,否則返回false
*/
public static boolean isPassword(String password) {
return Pattern.matches(REGEX_PASSWORD, password);
}
/**
* 校驗手機號
*
* @param mobile
* @return 校驗通過返回true,否則返回false
*/
public static boolean isMobile(String mobile) {
return Pattern.matches(REGEX_MOBILE, mobile);
}
/**
* 校驗郵箱
*
* @param email
* @return 校驗通過返回true,否則返回false
*/
public static boolean isEmail(String email) {
return Pattern.matches(REGEX_EMAIL, email);
}
}
com.hualinux.login.Login.java代碼如下:
package com.hualinux.login;
public abstract class Login {
//登陸頁面主題名,包括css、js、html等一系列外觀,
String theme="login.vue";
abstract Boolean login(String loginString,String password);
}
com.hualinux.login.LoginByEmail.java代碼如下:我這裏爲了方便設置密碼爲123則登錄成功
package com.hualinux.login;
public class LoginByEmail extends Login {
@Override
public Boolean login(String loginString, String password) {
if (password.equals("123")){
return true;
}else {
return false;
}
}
}
com.hualinux.login.LoginByTel.java代碼如下:
package com.hualinux.login;
public class LoginByTel extends Login{
@Override
public Boolean login(String loginString, String password) {
if (password.equals("123")){
return true;
}else {
return false;
}
}
}
com.hualinux.login.LoginByUsername.java代碼如下:
package com.hualinux.login;
public class LoginByUsername extends Login{
@Override
public Boolean login(String loginString, String password) {
if (password.equals("123")){
return true;
}else {
return false;
}
}
}
在這裏我得解釋一下,看上面LoginByEmail、LoginByTel、LoginByUsername是一樣的,但實際中是不一樣的
因爲要連接數據庫實現sql查詢,查詢的條件就不同,所以結果是不同的,密碼相同的
com.hualinux.login.LoginMain.java代碼如下:
package com.hualinux.login;
import java.util.Scanner;
public class LoginMain {
public static void main(String[] args) {
System.out.print("請輸入 用戶名/手機號/郵箱(回車結束):");
Scanner scan=new Scanner(System.in);
// 判斷是否還有輸入
String loginStr=scan.nextLine();
System.out.print("請輸入密碼(回車結束):");
String pwdStr=scan.nextLine();
scan.close();
Login login;
if (AccountValidatorUtil.isMobile(loginStr)){
System.out.println("tel");
login=new LoginByTel();
}else if (AccountValidatorUtil.isEmail(loginStr)){
System.out.println("email");
login=new LoginByEmail();
}else{
System.out.println("username");
login=new LoginByUsername();
}
//設置網站主題
login.theme="login-blue.vue";
if(login.login(loginStr,pwdStr)){
System.out.println("登陸成功");
}else {
System.out.println("登錄失敗");
}
}
}
2.2.3 效果
我以郵件爲例子:
先寫郵箱和正確的密碼,看是否判斷出是郵箱、判斷密碼是否正確,如下
我輸入 hua@163、密碼爲123,發現判斷出是email,並提示登錄成功了
我輸入 hua@163、密碼爲456,發現判斷出是email,並提示登錄失敗
2.3 使用模板的優缺點
優點:
1、封裝不變部分,擴展可變部分。
2、提取公共代碼,便於維護。
3、行爲由父類控制,子類實現。
缺點:
每一個不同的實現都需要一個子類來實現,導致類的個數增加,使得系統更加龐大。
使用場景:
1、有多個子類共有的方法,且邏輯相同。 2、重要的、複雜的方法,可以考慮作爲模板方法。
注意事項:
爲防止惡意操作,一般模板方法都加上 final 關鍵詞。
三、抽象類和接口類的區別
我這裏直接使用一張圖來說明
重要提示:
在開發中,一個類永遠不要去繼承一個已經實現好的類,要麼繼承抽象類,要麼實現接口,如果兩個類同時都可以使用的話,優先使用接口,避免單繼承的侷限。
抽象類和接口類總結
1、抽象類和接口類的實例化,通過多態性(向上轉型,向下轉型)。
2、抽象類表示一個模板,接口表示一個標準。
3、常見的設計模式:模板設計,工廠設計,代理設計,適配器設計。