自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MapStruct教程-三種方式處理繼承關(guān)系

開發(fā) 前端
MapStruct是一個(gè)效率工具,可以在處理Java Bean映射時(shí),幫助我們盡量減少樣板代碼,只需要定義接口,它會(huì)自動(dòng)生成映射邏輯。本文中,我們一起看下如何通過MapStruct處理集成關(guān)系。

你好,我是看山。

MapStruct是一個(gè)效率工具,可以在處理Java Bean映射時(shí),幫助我們盡量減少樣板代碼,只需要定義接口,它會(huì)自動(dòng)生成映射邏輯。本文中,我們一起看下如何通過MapStruct處理集成關(guān)系。

我們將討論三種方法:

  1. 通過實(shí)例檢查;
  2. 使用訪問者模式;
  3. 【推薦】使用@SubclassMapping注解。

一、背景

默認(rèn)情況下,MapStruct無法為所有從基類或接口繼承的類生成映射器,不支持運(yùn)行時(shí)識(shí)別實(shí)例和對象層次結(jié)構(gòu)。

(一)基礎(chǔ)定義

先定義POJO類:

public abstract class Vehicle {
    private String color;
    private String speed;
}

public class Car extends Vehicle{
    private Integer tires;
}

public class Bus extends Vehicle {
    private Integer capacity;
}

再定義對應(yīng)的DTO類:

public class VehicleDTO {
    private String color;
    private String speed;
}

public class CarDTO extends VehicleDTO{
    private Integer tires;
}

public class BusDTO extends VehicleDTO{
    private Integer capacity;
}

(二)定義映射器

這里我們定義三個(gè)映射器:CarMapper、BusMapper、VehicleMapper:

@Mapper
public interface CarMapper {
    CarDTO carToDTO(Car car);
}

@Mapper
public interface BusMapper {
    BusDTO busToDTO(Bus bus);
}

@Mapper(uses = {BusMapper.class, CarMapper.class})
public interface VehicleMapper {
    VehicleDTO vehicleToDTO(Vehicle vehicle);
}

在這里,我們分別定義了所有子類的映射器,并在基類映射器通過uses配置使用它們。

(三)識(shí)別問題

我們先看下VehicleMapper的生成類:

public class VehicleMapperImpl implements VehicleMapper {

    @Override
    public VehicleDTO vehicleToDTO(Vehicle vehicle) {
        if ( vehicle == null ) {
            return null;
        }

        VehicleDTO vehicleDTO = new VehicleDTO();

        vehicleDTO.setColor( vehicle.getColor() );
        vehicleDTO.setSpeed( vehicle.getSpeed() );

        return vehicleDTO;
    }
}

可以看到,代碼中是直接使用了VehicleDTO,并沒有用到子類的任何定義。我們可以在入口傳入Car或Bus的實(shí)例對象,但是最終得到的只能是VehicleDTO的實(shí)例。

二、通過實(shí)例檢查實(shí)現(xiàn)

我們一起看看如何通過實(shí)例檢查實(shí)現(xiàn)映射邏輯,因?yàn)楸容^簡單,直接代碼:

@Mapper
public interface VehicleMapperByInstanceChecks {
    CarDTO map(Car car);

    BusDTO map(Bus bus);

    default VehicleDTO mapToVehicleDTO(Vehicle vehicle) {
        if (vehicle instanceof Bus) {
            return map((Bus) vehicle);
        } else if (vehicle instanceof Car) {
            return map((Car) vehicle);
        } else {
            return null;
        }
    }
}

從上面代碼來說,其實(shí)完全是靠人工智能實(shí)現(xiàn)的,通過我們HardCode,借助instanceof實(shí)現(xiàn)類型判斷,轉(zhuǎn)換為需要的類型實(shí)例。

三、通過訪問者模式實(shí)現(xiàn)

第二種方式是借助訪問者模式實(shí)現(xiàn),通過Java的多態(tài),可以精準(zhǔn)的調(diào)用到需要的方法。

(一)應(yīng)用訪問者模式

首先在抽象類Vehicle中定義抽象方法accept(),以接受任何訪問者對象:

public abstract class Vehicle {
    public abstract VehicleDTO accept(Visitor visitor);
}

public interface Visitor {
    VehicleDTO visit(Car car);

    VehicleDTO visit(Bus bus);
}

現(xiàn)在,我們需要為每個(gè)Vehicle子類實(shí)現(xiàn)accept()方法:

public class Bus extends Vehicle {
    @Override
    VehicleDTO accept(Visitor visitor) {
        return visitor.visit(this);
    }
}

public class Car extends Vehicle {
    @Override
    VehicleDTO accept(Visitor visitor) {
        return visitor.visit(this);
    }
}

最后,我們可以通過實(shí)現(xiàn)訪問者接口來實(shí)現(xiàn)映射器:

@Mapper
public abstract class VehicleMapperByVisitorPattern implements Visitor {
    public VehicleDTO mapToVehicleDTO(Vehicle vehicle) {
        return vehicle.accept(this);
    }

    @Override
    public VehicleDTO visit(Car car) {
        return map(car);
    }

    @Override
    public VehicleDTO visit(Bus bus) {
        return map(bus);
    }

    abstract CarDTO map(Car car);

    abstract BusDTO map(Bus bus);
}

從性能來說,訪問者模式方法比實(shí)例檢查方法更優(yōu)化,借助Java的多態(tài)實(shí)現(xiàn),快速定位轉(zhuǎn)換方法。從代碼量來說,實(shí)例檢查會(huì)由于訪問者模式,因?yàn)閷懙纳佟?/p>

其實(shí)這里會(huì)引出一個(gè)問題,設(shè)計(jì)模式是好是壞?

四、使用@SubclassMapping實(shí)現(xiàn)

MapStruct提供了@SubclassMapping注解,允許我們配置的映射器,可以處理有繼承關(guān)系的類實(shí)例轉(zhuǎn)換。

@SubclassMapping注解中有source和target兩個(gè)配置,source定義要映射的源子類,target定義要映射到的目標(biāo)子類:

(一)定義

我們使用@SubclassMapping注解指定繼承對應(yīng)關(guān)系:

@Mapper(uses = {BusMapper.class, CarMapper.class})
public interface VehicleMapperBySubclassMapping {
    @SubclassMapping(source = Car.class, target = CarDTO.class)
    @SubclassMapping(source = Bus.class, target = BusDTO.class)
    VehicleDTO mapToVehicleDTO(Vehicle vehicle);
}

生成的映射代碼為:

public class VehicleMapperBySubclassMappingImpl implements VehicleMapperBySubclassMapping {

    private final BusMapper busMapper = Mappers.getMapper( BusMapper.class );
    private final CarMapper carMapper = Mappers.getMapper( CarMapper.class );

    @Override
    public VehicleDTO mapToVehicleDTO(Vehicle vehicle) {
        if ( vehicle == null ) {
            return null;
        }

        if (vehicle instanceof Car) {
            return carMapper.carToDTO( (Car) vehicle );
        }
        else if (vehicle instanceof Bus) {
            return busMapper.busToDTO( (Bus) vehicle );
        }
        else {
            VehicleDTO vehicleDTO = new VehicleDTO();

            vehicleDTO.setColor( vehicle.getColor() );
            vehicleDTO.setSpeed( vehicle.getSpeed() );

            return vehicleDTO;
        }
    }
}

可以看到,MapStruct自動(dòng)實(shí)現(xiàn)了實(shí)例檢查,通過instanceof判斷類型。

責(zé)任編輯:武曉燕 來源: 看山的小屋
相關(guān)推薦

2009-09-25 14:12:16

Hibernate繼承

2020-11-01 17:10:46

異步事件開發(fā)前端

2025-01-24 00:00:00

MapStruct子類型Mapper

2012-07-17 09:16:16

SpringSSH

2024-07-08 09:03:31

2025-01-13 00:00:00

MapStruct枚舉映射

2010-03-12 17:52:35

Python輸入方式

2014-07-30 17:10:38

LVS集群負(fù)載均衡

2009-07-03 18:32:18

JSP頁面跳轉(zhuǎn)

2014-12-31 17:42:47

LBSAndroid地圖

2021-06-24 08:52:19

單點(diǎn)登錄代碼前端

2021-11-05 21:33:28

Redis數(shù)據(jù)高并發(fā)

2019-11-20 18:52:24

物聯(lián)網(wǎng)智能照明智能恒溫器

2011-04-08 11:13:50

CISCO IOS令牌桶雙桶

2010-06-13 16:04:14

MySQL三種安裝方式

2025-01-16 00:00:00

MapStruct映射

2017-07-14 15:07:23

2015-01-16 17:41:45

數(shù)據(jù)中心模塊化

2010-09-13 12:19:03

2011-07-25 12:41:38

接入方式布線
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)