<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    優(yōu)化重復(fù)冗余代碼的8種方式!

    共 27533字,需瀏覽 56分鐘

     ·

    2023-08-31 01:25

    前言

    如果想學(xué)Java項(xiàng)目的,強(qiáng)烈推薦我的??項(xiàng)目消息推送平臺(tái)Austin8K stars),可以用作畢業(yè)設(shè)計(jì),可以用作校招,可以看看生產(chǎn)環(huán)境是怎么推送消息的。 

    倉(cāng)庫(kù)地址(可點(diǎn)擊閱讀原文跳轉(zhuǎn)):https://gitee.com/zhongfucheng/austin

    常開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到一些重復(fù)冗余的代碼。大家都知道重復(fù)代碼不好,它主要有這些缺點(diǎn):可維護(hù)性差、可讀性差、增加錯(cuò)誤風(fēng)險(xiǎn)等等。最近呢,我優(yōu)化了一些系統(tǒng)中的重復(fù)代碼,用了好幾種的方式,感覺(jué)挺有用的。所以本文給大家講講優(yōu)化重復(fù)冗余代碼的幾種方式~

    • 抽取公用方法
    • 抽個(gè)工具類
    • 反射
    • 泛型
    • 繼承和多態(tài)
    • 設(shè)計(jì)模式
    • 函數(shù)式Lambda
    • AOP切面

    1. 抽取公用方法

    抽取公用方法,是最常用的代碼去重方式~

    比如這個(gè)例子,分別遍歷names列表,然后各自轉(zhuǎn)化為大寫(xiě)和小寫(xiě)打印出來(lái):

    public class TianLuoExample {

        public static void main(String[] args) {
            List<String> names = Arrays.asList("Alice""Bob""Charlie""David""TianLuo");

            System.out.println("Uppercase Names:");
            for (String name : names) {
                String uppercaseName = name.toUpperCase();
                System.out.println(uppercaseName);
            }

            System.out.println("Lowercase Names:");
            for (String name : names) {
                String lowercaseName = name.toLowerCase();
                System.out.println(lowercaseName);
            }
        }
    }

    顯然,都是遍歷names過(guò)程,代碼是重復(fù)冗余的,只不過(guò)轉(zhuǎn)化大小寫(xiě)不一樣而已。我們可以抽個(gè)公用方法processNames,優(yōu)化成這樣:

    public class TianLuoExample {

        public static void processNames(List<String> names, Function<String, String> nameProcessor, String processType) {
            System.out.println(processType + " Names:");
            for (String name : names) {
                String processedName = nameProcessor.apply(name);
                System.out.println(processedName);
            }
        }

        public static void main(String[] args) {
            List<String> names = Arrays.asList("Alice""Bob""Charlie""David""TianLuo");

            processNames(names, String::toUpperCase, "Uppercase");
            processNames(names, String::toLowerCase, "Lowercase");
        }
    }

    2. 抽工具類

    我們優(yōu)化重復(fù)代碼,抽一個(gè)公用方法后,如果發(fā)現(xiàn)這個(gè)方法有更多共性,就可以把公用方法升級(jí)為一個(gè)工具類。比如這樣的業(yè)務(wù)場(chǎng)景:注冊(cè),修改郵箱,重置密碼等,都需要校驗(yàn)郵箱

    實(shí)現(xiàn)注冊(cè)功能時(shí),用戶會(huì)填郵箱,需要驗(yàn)證郵箱格式,

    public class RegisterServiceImpl implements RegisterService{
        private static final String EMAIL_REGEX =
            "^[A-Za-z0-9+_.-]+@(.+)$";

        public boolean registerUser(UserInfoReq userInfo) {
            String email = userInfo.getEmail();
            Pattern pattern = Pattern.compile(EMAIL_REGEX);
            Matcher emailMatcher = pattern.matcher(email);
            if (!emailMatcher.matches()) {
                System.out.println("Invalid email address.");
                return false;
            }

            // 進(jìn)行其他用戶注冊(cè)邏輯,比如保存用戶信息到數(shù)據(jù)庫(kù)等
            // 返回注冊(cè)結(jié)果
            return true;
        }
    }

    密碼重置流程中,通常會(huì)向用戶提供一個(gè)鏈接或驗(yàn)證碼,并且需要發(fā)送到用戶的電子郵件地址。在這種情況下,也需要驗(yàn)證郵箱格式合法性

    public class PasswordServiceImpl implements PasswordService{

        private static final String EMAIL_REGEX =
            "^[A-Za-z0-9+_.-]+@(.+)$";

        public void resetPassword(PasswordInfo passwordInfo) {
            Pattern pattern = Pattern.compile(EMAIL_REGEX);
            Matcher emailMatcher = pattern.matcher(passwordInfo.getEmail());
            if (!emailMatcher.matches()) {
                System.out.println("Invalid email address.");
                return false;
            }
            //發(fā)送通知修改密碼
            sendReSetPasswordNotify();
        }
    }

    我們可以抽取個(gè)校驗(yàn)郵箱的方法出來(lái),又因?yàn)樾r?yàn)郵箱的功能在不同的類中,因此,我們可以抽個(gè)校驗(yàn)郵箱的工具類

    public class EmailValidatorUtil {
        private static final String EMAIL_REGEX =
            "^[A-Za-z0-9+_.-]+@(.+)$";

        private static final Pattern pattern = Pattern.compile(EMAIL_REGEX);

        public static boolean isValid(String email) {
            Matcher matcher = pattern.matcher(email);
            return matcher.matches();
        }
    }

    //注冊(cè)的代碼可以簡(jiǎn)化為這樣啦
    public class RegisterServiceImpl implements RegisterService{
        
        public boolean registerUser(UserInfoReq userInfo) {
            if (!EmailValidatorUtil.isValid(userInfo.getEmail())) {
                System.out.println("Invalid email address.");
                return false;
            }

            // 進(jìn)行其他用戶注冊(cè)邏輯,比如保存用戶信息到數(shù)據(jù)庫(kù)等
            // 返回注冊(cè)結(jié)果
            return true;
        }
    }

    3. 反射

    我們?nèi)粘i_(kāi)發(fā)中,經(jīng)常需要進(jìn)行PO、DTO和VO的轉(zhuǎn)化。所以大家經(jīng)??吹筋愃频拇a:

        //DTO 轉(zhuǎn)VO
        public UserInfoVO convert(UserInfoDTO userInfoDTO) {
            UserInfoVO userInfoVO = new UserInfoVO();
            userInfoVO.setUserName(userInfoDTO.getUserName());
            userInfoVO.setAge(userInfoDTO.getAge());
            return userInfoVO;
        }
          //PO 轉(zhuǎn)DTO
        public UserInfoDTO convert(UserInfoPO userInfoPO) {
            UserInfoDTO userInfoDTO = new UserInfoDTO();
            userInfoDTO.setUserName(userInfoPO.getUserName());
            userInfoDTO.setAge(userInfoPO.getAge());
            return userInfoDTO;
        }

    我們可以使用BeanUtils.copyProperties() 去除重復(fù)代碼BeanUtils.copyProperties()底層就是使用了反射

        public UserInfoVO convert(UserInfoDTO userInfoDTO) {
            UserInfoVO userInfoVO = new UserInfoVO();
            BeanUtils.copyProperties(userInfoDTO, userInfoVO);
            return userInfoVO;
        }

        public UserInfoDTO convert(UserInfoPO userInfoPO) {
            UserInfoDTO userInfoDTO = new UserInfoDTO();
            BeanUtils.copyProperties(userInfoPO,userInfoDTO);
            return userInfoDTO;
        }

    4.泛型

    泛型是如何去除重復(fù)代碼的呢?給大家看個(gè)例子,我有個(gè)轉(zhuǎn)賬明細(xì)和轉(zhuǎn)賬余額對(duì)比的業(yè)務(wù)需求,有兩個(gè)類似這樣的方法:

    private void getAndUpdateBalanceResultMap(String key, Map<String, List<TransferBalanceDTO>> compareResultListMap,
    List<TransferBalanceDTO> balanceDTOs) {
        List<TransferBalanceDTO> tempList = compareResultListMap.getOrDefault(key, new ArrayList<>());
        tempList.addAll(balanceDTOs);
        compareResultListMap.put(key, tempList);
    }

    private void getAndUpdateDetailResultMap(String key, Map<String, List<TransferDetailDTO>> compareResultListMap,
                                              List<TransferDetailDTO> detailDTOS) {
        List<TransferDetailDTO> tempList = compareResultListMap.getOrDefault(key, new ArrayList<>());
        tempList.addAll(detailDTOS);
        compareResultListMap.put(key, tempList);
    }

    這兩塊代碼,流程功能看著很像,但是就是不能直接合并抽取一個(gè)公用方法,因?yàn)轭愋筒灰恢?/strong>。單純類型不一樣的話,我們可以結(jié)合泛型處理,因?yàn)榉盒偷谋举|(zhì)就是參數(shù)化類型.優(yōu)化為這樣:

    private <T> void getAndUpdateResultMap(String key, Map<String, List<T>> compareResultListMap, List<T> accountingDTOS) {
    List<T> tempList = compareResultListMap.getOrDefault(key, new ArrayList<>());
    tempList.addAll(accountingDTOS);
    compareResultListMap.put(key, tempList);
    }

    5. 繼承與多態(tài)

    假設(shè)你正在開(kāi)發(fā)一個(gè)電子商務(wù)平臺(tái),需要處理不同類型的訂單,例如普通訂單和折扣訂單。每種訂單都有一些共同的屬性(如訂單號(hào)、購(gòu)買(mǎi)商品列表)和方法(如計(jì)算總價(jià)、生成訂單報(bào)告),但折扣訂單還有特定的屬性和方法。

    在沒(méi)有使用繼承和多態(tài)的話,會(huì)寫(xiě)出類似這樣的代碼:

    //普通訂單
    public class Order {
        private String orderNumber;
        private List<Product> products;

        public Order(String orderNumber, List<Product> products) {
            this.orderNumber = orderNumber;
            this.products = products;
        }

        public double calculateTotalPrice() {
            double total = 0;
            for (Product product : products) {
                total += product.getPrice();
            }
            return total;
        }
        
          public String generateOrderReport() {
            return "Order Report for " + orderNumber + ": Total Price = $" + calculateTotalPrice();
        }
    }

    //折扣訂單
    public class DiscountOrder {
        private String orderNumber;
        private List<Product> products;
        private double discountPercentage;

        public DiscountOrder(String orderNumber, List<Product> products, double discountPercentage) {
            this.orderNumber = orderNumber;
            this.products = products;
            this.discountPercentage = discountPercentage;
        }

        public double calculateTotalPrice() {
            double total = 0;
            for (Product product : products) {
                total += product.getPrice();
            }
            return total - (total * discountPercentage / 100);
        }
          public String generateOrderReport() {
            return "Order Report for " + orderNumber + ": Total Price = $" + calculateTotalPrice();
        }
    }

    顯然,看到在OrderDiscountOrder類中,generateOrderReport() 方法的代碼是完全相同的。calculateTotalPrice()則是有一點(diǎn)點(diǎn)區(qū)別,但也大相徑庭。

    我們可以使用繼承和多態(tài)去除重復(fù)代碼,讓DiscountOrder去繼承Order,代碼如下:

    public class Order {
        private String orderNumber;
        private List<Product> products;

        public Order(String orderNumber, List<Product> products) {
            this.orderNumber = orderNumber;
            this.products = products;
        }

        public double calculateTotalPrice() {
            double total = 0;
            for (Product product : products) {
                total += product.getPrice();
            }
            return total;
        }

        public String generateOrderReport() {
            return "Order Report for " + orderNumber + ": Total Price = $" + calculateTotalPrice();
        }
    }

    public class DiscountOrder extends Order {
        private double discountPercentage;

        public DiscountOrder(String orderNumber, List<Product> products, double discountPercentage) {
            super(orderNumber, products);
            this.discountPercentage = discountPercentage;
        }

        @Override
        public double calculateTotalPrice() {
            double total = super.calculateTotalPrice();
            return total - (total * discountPercentage / 100);
        }
    }

    6.使用設(shè)計(jì)模式

    很多設(shè)計(jì)模式可以減少重復(fù)代碼、提高代碼的可讀性、可擴(kuò)展性.比如:

    • 工廠模式: 通過(guò)工廠模式,你可以將對(duì)象的創(chuàng)建和使用分開(kāi),從而減少重復(fù)的創(chuàng)建代碼。
    • 策略模式: 策略模式定義了一族算法,將它們封裝成獨(dú)立的類,并使它們可以互相替換。通過(guò)使用策略模式,你可以減少在代碼中重復(fù)使用相同的邏輯。
    • 模板方法模式:模板方法模式定義了一個(gè)算法的骨架,將一些步驟延遲到子類中實(shí)現(xiàn)。這有助于避免在不同類中重復(fù)編寫(xiě)相似的代碼

    我給大家舉個(gè)例子,模板方法是如何去除重復(fù)代碼的吧,業(yè)務(wù)場(chǎng)景:

    假設(shè)你正在開(kāi)發(fā)一個(gè)咖啡和茶的制作流程,制作過(guò)程中的熱水和添加物質(zhì)的步驟是相同的,但是具體的飲品制作步驟是不同的。

    如果沒(méi)有使用模板方法模式,實(shí)現(xiàn)是醬紫的:

    public class Coffee {
        public void prepareCoffee() {
            boilWater();
            brewCoffeeGrinds();
            pourInCup();
            addCondiments();
        }

        private void boilWater() {
            System.out.println("Boiling water");
        }

        private void brewCoffeeGrinds() {
            System.out.println("Brewing coffee grinds");
        }

        private void pourInCup() {
            System.out.println("Pouring into cup");
        }

        private void addCondiments() {
            System.out.println("Adding sugar and milk");
        }
    }

    public class Tea {
        public void prepareTea() {
            boilWater();
            steepTeaBag();
            pourInCup();
            addLemon();
        }

        private void boilWater() {
            System.out.println("Boiling water");
        }

        private void steepTeaBag() {
            System.out.println("Steeping the tea bag");
        }

        private void pourInCup() {
            System.out.println("Pouring into cup");
        }

        private void addLemon() {
            System.out.println("Adding lemon");
        }
    }

    這個(gè)代碼例子,我們可以發(fā)現(xiàn),燒水和倒入杯子的步驟代碼,在CoffeeTea類中是重復(fù)的。

    使用模板方法模式,代碼可以優(yōu)化成這樣:

    abstract class Beverage {
        public final void prepareBeverage() {
            boilWater();
            brew();
            pourInCup();
            addCondiments();
        }

        private void boilWater() {
            System.out.println("Boiling water");
        }

        abstract void brew();

        private void pourInCup() {
            System.out.println("Pouring into cup");
        }

        abstract void addCondiments();
    }

    class Coffee extends Beverage {
        @Override
        void brew() {
            System.out.println("Brewing coffee grinds");
        }

        @Override
        void addCondiments() {
            System.out.println("Adding sugar and milk");
        }
    }

    class Tea extends Beverage {
        @Override
        void brew() {
            System.out.println("Steeping the tea bag");
        }

        @Override
        void addCondiments() {
            System.out.println("Adding lemon");
        }
    }

    在這個(gè)例子中,我們創(chuàng)建了一個(gè)抽象類Beverage,其中定義了制作飲品的模板方法 prepareBeverage()。這個(gè)方法包含了燒水、倒入杯子等共同的步驟,而將制作過(guò)程中的特定步驟 brew() 和 addCondiments() 延遲到子類中實(shí)現(xiàn)。這樣,我們避免了在每個(gè)具體的飲品類中重復(fù)編寫(xiě)相同的燒水和倒入杯子的代碼,提高了代碼的可維護(hù)性和重用性。

    7.自定義注解(或者說(shuō)AOP面向切面)

    使用 AOP框架可以在不同地方插入通用的邏輯,從而減少代碼重復(fù)。

    業(yè)務(wù)場(chǎng)景:

    假設(shè)你正在開(kāi)發(fā)一個(gè)Web應(yīng)用程序,需要對(duì)不同的Controller方法進(jìn)行權(quán)限檢查。每個(gè)Controller方法都需要進(jìn)行類似的權(quán)限驗(yàn)證,但是重復(fù)的代碼會(huì)導(dǎo)致代碼的冗余和維護(hù)困難。

    public class MyController {
        public void viewData() {
            if (!User.hasPermission("read")) {
                throw new SecurityException("Insufficient permission to access this resource.");
            }
            // Method implementation
        }

        public void modifyData() {
            if (!User.hasPermission("write")) {
                throw new SecurityException("Insufficient permission to access this resource.");
            }
            // Method implementation
        }
    }

    你可以看到在每個(gè)需要權(quán)限校驗(yàn)的方法中都需要重復(fù)編寫(xiě)相同的權(quán)限校驗(yàn)邏輯,即出現(xiàn)了重復(fù)代碼.我們使用自定義注解的方式能夠?qū)?quán)限校驗(yàn)邏輯集中管理,通過(guò)切面來(lái)處理,消除重復(fù)代碼.如下:

    @Aspect
    @Component
    public class PermissionAspect {

        @Before("@annotation(requiresPermission)")
        public void checkPermission(RequiresPermission requiresPermission) {
            String permission = requiresPermission.value();
            
            if (!User.hasPermission(permission)) {
                throw new SecurityException("Insufficient permission to access this resource.");
            }
        }
    }

    public class MyController {
        @RequiresPermission("read")
        public void viewData() {
            // Method implementation
        }

        @RequiresPermission("write")
        public void modifyData() {
            // Method implementation
        }
    }

    就這樣,不管多少個(gè)Controller方法需要進(jìn)行權(quán)限檢查,你只需在方法上添加相應(yīng)的注解即可。權(quán)限檢查的邏輯在切面中集中管理,避免了在每個(gè)Controller方法中重復(fù)編寫(xiě)相同的權(quán)限驗(yàn)證代碼。這大大提高了代碼的可讀性、可維護(hù)性,并避免了代碼冗余。

    8.函數(shù)式接口和Lambda表達(dá)式

    業(yè)務(wù)場(chǎng)景:

    假設(shè)你正在開(kāi)發(fā)一個(gè)應(yīng)用程序,需要根據(jù)不同的條件來(lái)過(guò)濾一組數(shù)據(jù)。每次過(guò)濾的邏輯都可能會(huì)有些微的不同,但基本的流程是相似的。

    沒(méi)有使用函數(shù)式接口和Lambda表達(dá)式的情況:

    public class DataFilter {
        public List<Integer> filterPositiveNumbers(List<Integer> numbers) {
            List<Integer> result = new ArrayList<>();
            for (Integer number : numbers) {
                if (number > 0) {
                    result.add(number);
                }
            }
            return result;
        }

        public List<Integer> filterEvenNumbers(List<Integer> numbers) {
            List<Integer> result = new ArrayList<>();
            for (Integer number : numbers) {
                if (number % 2 == 0) {
                    result.add(number);
                }
            }
            return result;
        }
    }

    在這個(gè)例子中,我們有兩個(gè)不同的方法來(lái)過(guò)濾一組數(shù)據(jù),但是基本的循環(huán)和條件判斷邏輯是重復(fù)的,我們可以使用使用函數(shù)式接口和Lambda表達(dá)式,去除重復(fù)代碼,如下:

    public class DataFilter {
        public List<Integer> filterNumbers(List<Integer> numbers, Predicate<Integer> predicate) {
            List<Integer> result = new ArrayList<>();
            for (Integer number : numbers) {
                if (predicate.test(number)) {
                    result.add(number);
                }
            }
            return result;
        }
    }

    我們將過(guò)濾的核心邏輯抽象出來(lái)。該方法接受一個(gè) Predicate函數(shù)式接口作為參數(shù),以便根據(jù)不同的條件來(lái)過(guò)濾數(shù)據(jù)。然后,我們可以使用Lambda表達(dá)式來(lái)傳遞具體的條件,這樣最終也達(dá)到去除重復(fù)代碼的效果啦.

    END


    Java項(xiàng)目訓(xùn)練營(yíng)

    我開(kāi)通了項(xiàng)目股東服務(wù),已經(jīng)有不少消息推送平臺(tái)項(xiàng)目股東拿了阿里/vivo等大廠offer了。我是沒(méi)找到網(wǎng)上有跟我提供相同的服務(wù),價(jià)格還比我低的。

    ??一對(duì)一周到的服務(wù):有很多人的自學(xué)能力和基礎(chǔ)確實(shí)不太行,不知道怎么開(kāi)始學(xué)習(xí),從哪開(kāi)始看起,學(xué)習(xí)項(xiàng)目的過(guò)程中會(huì)走很多彎路,很容易就迷茫了。付費(fèi)最跟自學(xué)最主要的區(qū)別就是我的服務(wù)會(huì)更周到。我會(huì)告訴你怎么開(kāi)始學(xué)這個(gè)開(kāi)源項(xiàng)目,哪些是重點(diǎn)需要掌握的,如何利用最短的時(shí)間把握整個(gè)系統(tǒng)架構(gòu)和編碼的設(shè)計(jì),把時(shí)間節(jié)省下來(lái)去做其他事情。學(xué)習(xí)經(jīng)驗(yàn)/路線/簡(jiǎn)歷編寫(xiě)/面試經(jīng)驗(yàn)知無(wú)不言

    ??本地直連遠(yuǎn)程服務(wù):生產(chǎn)環(huán)境的應(yīng)用系統(tǒng)肯定會(huì)依賴各種中間件,我專門(mén)買(mǎi)了兩臺(tái)服務(wù)器已經(jīng)搭建好必要的環(huán)境??,在本地就可以直接啟動(dòng)運(yùn)行體驗(yàn)和學(xué)習(xí),無(wú)須花額外的時(shí)間自行搭建調(diào)試。

    ??細(xì)致的文檔&視頻:巨細(xì)致的語(yǔ)雀文檔11W+ 字,共106個(gè)文檔,項(xiàng)目視頻還在持續(xù)制作更新中(20個(gè)),不怕你學(xué)不會(huì)。

    ??付費(fèi)社群優(yōu)質(zhì)的社群里需篩選過(guò)濾,學(xué)習(xí)氛圍是很重要的,多跟同輩或前輩聊聊,會(huì)少走很多彎路??

    ??清爽干練commit:專屬股東倉(cāng)庫(kù),一步一步從零復(fù)現(xiàn)austin,每個(gè)commit都帶著文檔&視頻學(xué)習(xí)。

    如果想獲取上面的權(quán)益,可以看看??Java項(xiàng)目訓(xùn)練營(yíng)

    瀏覽 3671
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    日本一区二区福利视频 | 亚洲精品黄色视频 | 国产黄色电影免费在线观看 | 欧美日韩激情在线 | 88国产精品视频一区二区三区 |