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

huangapple go评论69阅读模式
英文:

Add object to list based on the object type

问题

Requested state:

@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) {
        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);
        }
    }

}
英文:

I have a class that stores objects in lists. I have 3 different types of lists and I want to save the object in their respective list. As you can see, I have to repeat the method 3 times, once for each type, although in each case, the method does exactly the same thing.

Question:

Is there a way to write the same functionality with just one method using for example generics or interface?

Original code:

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

    // 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);
    }

}

Requested state:

@Repository
public class ItemsInMemoryDao {

    static List&lt;MyCompany&gt; companies = new ArrayList&lt;&gt;();
    static List&lt;Financial&gt; financials = new ArrayList&lt;&gt;();
    static List&lt;Stock&gt; stocks = new ArrayList&lt;&gt;();;

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

}

答案1

得分: 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语句看起来对我来说只是不必要的混乱。有没有任何理由你需要把一切都合并到一个方法中?如果是我,除非有其他原因,我会保持你原来的方式。

英文:

Any reason you couldn't just use instanceof? Here's one possible implementation:

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();
    }
}

That said, I can't say I really like this implementation. The chained else/ifs just look unnecessarily messy to me. Is there any reason you need to consolidate everything into one method? If it was me, and there was no reason to do otherwise, I would just leave it the way you had it.

答案2

得分: 1

请注意,由于格式限制,我无法一一保留原始代码的排版。以下是您提供的内容的翻译部分:

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

然而,在save方法中不重复自己,您可以像您已经建议的那样,使用抽象超类和泛型:

public abstract class InMemoryRepo<T> {
    
    // 注意:这里通常不需要 'static'。
    // @Repository 表示您的DAO将被创建并管理为单例bean,对吗?
    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>{

}

希望对您有所帮助。如果您有其他需要翻译的内容,请随时提供。

英文:

Don't repeat yourself is often a good idea. But, although this one method is the same for all items, I suggest to create a seperate DAO class for each item type. When future methods are added, such mixed classes will likely become bloated.

However, to not repeat yourself in the save method, you could use an abstract super class and generics as you suggested already:

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

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

@Repository
public class CompanyInMemoryDao extends InMemoryRepo&lt;MyCompany&gt;{

}

@Repository
public class FinancialInMemoryDao extends InMemoryRepo&lt;Financial&gt;{

}

@Repository
public class StockInMemoryDao extends InMemoryRepo&lt;Stock&gt;{

}

答案3

得分: 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);
}

可以真正用一个方法实现吗?
是的,可以在实现中使用 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("参数具有未知类型:" + object.getClass().getName());
}

例如,如果调用者尝试调用 save("Foo"),第一种解决方案将无法编译,因此您立即知道出现了问题,而第二种解决方案将编译通过,只有在尝试运行相关代码时才会意识到问题。

英文:

> Is there a way to write the same functionality with just one method using for example generics or interface?

Yes, and no but yes but don't do it.

Can it be done with "one" method called save?
Yes, using method overloading.
This is the recommended approach.

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

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

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

Can it be done with truly one method?
Yes, using instanceof in the implementation.
This is highly discouraged, since you will lose the type-safety of 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(&quot;Argument is of unknown type: &quot; + object.getClass().getName());
}

E.g. if a caller tries to call save(&quot;Foo&quot;), the first solution will fail to compile, so you instantly knows something it wrong, while the second solution will compile just fine, and you don't know something is wrong until you try running the code in question.

答案4

得分: 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( );
    }
}

我已确认这在这个实验中起作用...

...    
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

您可以在此处看到两种方法都成功运行

英文:

> „…Is there a way to write the same functionality with just one method using for example generics or interface?…

The simplest way to do what you require is the latter…

public interface Saveable { 

    long getId( );

    void setId( long id );
}

Then to further reduce duplication of code…

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; }
}

Your entities would extend that…

public class MyCompany extends AbstractSaveable { … }

public class Financial extends AbstractSaveable { … }

public class Stock extends AbstractSaveable { … }

So the only generics you really, truly need in such a simple use-case are the built-in ones…

…
public class ItemsInMemoryDao { 

    static private List&lt; Saveable &gt; db = new ArrayList&lt; &gt;( );    
    
    public void save( Saveable ntt ) {
        db.add( ntt ); 
    }

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

I've confirmed that this works in this experiment

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

dao.save( new Financial( 2 ) );

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

Of course, you could always <strike>over-engineer it</strike> use generics…

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

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

…To get the same result…

…
OverEngineeredDao&lt; Saveable &gt; oeDao = new OverEngineeredDao&lt; &gt;( );
    
oeDao.save( new MyCompany( 1 ) );

oeDao.save( new Financial( 2 ) );

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

Which I print out to confirm it works…

                                 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

You can see both approaches successfully running here.

huangapple
  • 本文由 发表于 2020年9月22日 05:25:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/64000186.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定