根据对象类型将对象添加到列表

时间:2020-09-21 21:25:02

标签: java generics

我有一个将对象存储在列表中的类。我有3种不同类型的列表,我想将对象保存在各自的列表中。如您所见,我必须重复该方法3次,每种类型重复一次,尽管在每种情况下,该方法执行的功能完全相同。

问题:

是否有一种方法可以仅使用一种方法(例如泛型或接口)来编写相同的功能?

原始代码:

@Repository
public class ItemsInMemoryDao {
    
    static List<MyCompany> companies = new ArrayList<>();
    static List<Financial> financials = new ArrayList<>();
    static List<Stock> stocks = new ArrayList<>();;

    // TODO: Rewrite using generics or interface?
    static void saveCompany(MyCompany company) {
        companies.add(company);
    }

    static void saveFinancial(Financial financial) {
        financials.add(financial);
    }

    static void saveStock(Stock stock) {
        stocks.add(stock);
    }

}

请求的状态:

@Repository
public class ItemsInMemoryDao {

    static List<MyCompany> companies = new ArrayList<>();
    static List<Financial> financials = new ArrayList<>();
    static List<Stock> stocks = new ArrayList<>();;

    static void save(Object object) {
        // implementation here 
    }

}

4 个答案:

答案 0 :(得分:2)

您为什么不能仅使用instanceof?这是一种可能的实现方式:

static void save(Object object) {
    if (object instanceof MyCompany) {
        companies.add((MyCompany) object);
    } else if (object instanceof Financial) {
        financials.add((Financial) object);
    } else if (object instanceof Stock) {
        stocks.add((Stock) object);
    } else {
        throw new IllegalArgumentException();
    }
}

也就是说,我不能说我真的很喜欢这种实现。串连的else / if看起来对我来说不必要。您是否有任何理由需要将所有内容合并为一种方法?如果是我,并且没有其他理由,我将按照您的方式进行处理。

答案 1 :(得分:1)

不重复自己通常是个好主意。但是,尽管此方法对于所有项目都是相同的,但我建议为每种项目类型创建一个单独的DAO类。当添加将来的方法时,此类混合类可能会变得肿。

但是,为了不重复使用save方法,您可以使用已经建议的抽象超类和泛型:

public abstract class InMemoryRepo<T> {
    
    // note: 'static' is typically not needed here.
    // @Repository indicates that your DAO will be created and managed as a signelton bean right?
    private List<T> items = new ArrayList<>();

    public void save(T item){
        items.add(item);
    }
}

@Repository
public class CompanyInMemoryDao extends InMemoryRepo<MyCompany>{

}

@Repository
public class FinancialInMemoryDao extends InMemoryRepo<Financial>{

}

@Repository
public class StockInMemoryDao extends InMemoryRepo<Stock>{

}

答案 2 :(得分:1)

是否有一种方法可以仅使用一种方法(例如泛型或接口)来编写相同的功能?

是的,不是,但是是的,但是不要这样做。

可以使用称为“ save”的“一个”方法来完成吗?
是的,使用方法重载。
这是推荐方法。

static void save(MyCompany company) {
    companies.add(company);
}

static void save(Financial financial) {
    financials.add(financial);
}

static void save(Stock stock) {
    stocks.add(stock);
}

可以用真正的 one 方法完成吗?
是的,在实现中使用instanceof
强烈建议,因为您将失去Java的类型安全性。

static void save(Object object) {
    if (object instanceof MyCompany)
        companies.add((MyCompany) company);
    else if (object instanceof Financial)
        financials.add((Financial) company);
    else if (object instanceof Stock)
        stocks.add((Stock) company);
    else
        throw new IllegalArgumentException("Argument is of unknown type: " + object.getClass().getName());
}

例如如果调用者尝试调用save("Foo"),则第一个解决方案将无法编译,因此您会立即知道出问题了,而第二个解决方案将编译得很好,并且直到您尝试运行时才知道出了什么问题有问题的代码。

答案 3 :(得分:0)

...是否有一种方法可以使用例如泛型或接口的一种方法来编写相同的功能?……

完成您所需要的最简单的方法就是后者……

public interface Saveable { 

    long getId( );

    void setId( long id );
}

然后进一步减少代码重复...

public abstract class AbstractSaveable implements Saveable {
    
    protected long id;
    
    @Override
    public long getId( ){ return this.id; }
    
    @Override
    public void setId( long id ){ this.id = id; }
}

您的实体将扩展……

public class MyCompany extends AbstractSaveable { … }

public class Financial extends AbstractSaveable { … }

public class Stock extends AbstractSaveable { … }

因此,在如此简单的用例中,您真正真正地 需要 的唯一泛型是内置的……

…
public class ItemsInMemoryDao { 

    static private List< Saveable > db = new ArrayList< >( );    
    
    public void save( Saveable ntt ) {
        db.add( ntt ); 
    }

    public Optional< Saveable > findById( final long id ) { 
        return db.stream( ).filter( ntt -> ntt.getId( ) == id ).findFirst( );
    }
}

我已经确认此方法有效in this experiment

…    
ItemsInMemoryDao dao = new ItemsInMemoryDao( );
    
dao.save( new MyCompany( 1 ) );

dao.save( new Financial( 2 ) );

dao.save( new Stock( 3 ) );
…

当然,您总是可以 对其进行过度设计 使用泛型…

public class OverEngineeredDao< NTT extends Saveable > { 
    
    private List< NTT > db = new ArrayList< >( );   
    
    public void save( NTT ntt ){
        
        db.add( ntt );
    }

    public Optional< NTT > findById( final long id ) { 
        return db.stream( ).filter( ntt -> ntt.getId( ) == id ).findFirst( );
    }
}

…要获得相同的结果…

…
OverEngineeredDao< Saveable > oeDao = new OverEngineeredDao< >( );
    
oeDao.save( new MyCompany( 1 ) );

oeDao.save( new Financial( 2 ) );

oeDao.save( new Stock( 3 ) );
…

我打印出来以确认它可以正常工作...

                                 Optional[MyCompany [ id: 1 ]]
                                 Optional[Financial [ id: 2 ]]
                                     Optional[Stock [ id: 3 ]]
                                 Optional[MyCompany [ id: 1 ]]
                                 Optional[Financial [ id: 2 ]]
                                     Optional[Stock [ id: 3 ]]
                                         EXPERIMENT SUCCESSFUL

您可以see both approaches successfully running here