使用Java中的顺序存储各种对象类型

时间:2018-04-11 15:17:19

标签: java oop

我正在尝试用Java建模太阳能系统,并且需要存储不同随机数量的对象类型并以某种方式保留它们的顺序。我目前正在使用以下类结构:

class PlanetarySystem - currently has a list of each object type (below)

class planetaryBody
         class star extends planetaryBody
         class planet extends planetaryBody
         class belt extends planetaryBody
         class disk extends planetaryBody

例如,假设我想通过系统循环显示PlaneitaryBody对象的详细信息。 Star的统计数据可能与Planet不同,依此类推。这是一个简单的例子。

public class PlanetaryBody
{
     private String name;

     public PlanetaryBody()
     {
          this.name = "Generic Name";
     }

     public String getName()
     {
          return this.name;
     }
}

public class Star extends PlanetaryBody
{
     private int temperature;

     public Star()
     {
          this.temperature = 12345;
     }
     public String getTemp()
     {
          return this.getTemp();
     }

}

现在,如果我稍后创建类似

的内容
List<planetaryBody> system = new List<planetaryBody>();
//then put some stars, planets, disks, etc in.
system.get(x).getName() //will work
system.get(x).getTemp() //will not work because type is planetaryBody

后来我想循环浏览列表然后让我们说出一切的名称,恒星的温度,皮带的大小,行星的颜色等等。我认为我不会拉出子类的特定函数。这是我试图解决的问题。

我可以创建一些东西,允许我按顺序存储对象,保留它们的内容,然后再对该类进行特定的操作吗?

我正在考虑尝试使用地图树,但我想我必须将它与planetBody类型一起使用。当我试图将物体拉出来并将它们作为行星体出来时,这会产生问题。我已经读过,做if语句来弄清楚它们是什么类不是最好的OOP练习,老实说我甚至都不知道这是否会按预期工作。

我是新人,学习,所以举例,并进一步阅读。

编辑:更多说明。

1 个答案:

答案 0 :(得分:1)

您的问题有很多解决方案,每个解决方案各有利弊,也有很多意见。我只是想提出一个老技巧,这里结合现代public class NavigationBarManager extends RecyclerView.Adapter<NavigationBarManager.FilterItemHolder> implements OnItemSelectedListener, AnimatorListener{//, Observer { private static final String TAG = "NavigationBarManager"; private RecyclerView mRecyclerView ; private int mSelectedItem = 0; private NotificationHandler mAnimNtfHandler; public static final int DIRECTION_LEFT = -1; public static final int DIRECTION_RIGHT = 1; Context mContext; FilterItemHolder mFilterItemHolder; private ArrayList<String> mFilterStringList; private ArrayList<Drawable> mFilterDrawableList; private ArrayList<Integer> mCursorIdxList; private ArrayList<Integer> mFilterIdList; private HtvChannelListUtil mListUtil; private ITvSettingsManager mSettings; private RecyclerView.SmoothScroller smoothScroller; private LinearLayoutManager mRecyclerViewMgr = null; public NavigationBarManager(Context context) { mContext = context; mAnimNtfHandler = NotificationHandler.getInstance(); mFilterStringList = new ArrayList<String>(); mFilterDrawableList = new ArrayList<Drawable>(); mFilterIdList = new ArrayList<Integer>(); mCursorIdxList = new ArrayList<Integer>(); mListUtil = HtvChannelListUtil.getInstance(); mSettings = ITvSettingsManager.Instance.getInterface(); mCacheManager = HtvChannelCacheManager.getInstance(); mFillDataIntoNavigationBar(); mNtfHandler = NotificationHandler.getInstance(); } public void setLayoutManager(LinearLayoutManager pRecyclerViewMgr) { mRecyclerViewMgr = pRecyclerViewMgr; } public class FilterItemHolder extends RecyclerView.ViewHolder { ImageView imageView; //ImageView mBgView; public FilterItemHolder(View itemView) { super(itemView); // get the reference of item view's imageView=(ImageView) itemView.findViewById(R.id.imageview); //mBgView = (ImageView) itemView.findViewById(R.id.bgView); } } @Override public FilterItemHolder onCreateViewHolder(ViewGroup parent, int viewType) { Log.e(TAG,"onCreateViewHolder viewType" +viewType); View lViewHolder = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); FilterItemHolder lHolder = new FilterItemHolder(lViewHolder); mFilterItemHolder = lHolder; return lHolder; } @Override public void onBindViewHolder(FilterItemHolder holder, final int position) { Log.e(TAG,"onBindViewHolder position=" +position); Log.e(TAG,"onBindViewHolder getAdapterPosition=" +holder.getAdapterPosition()); Log.e(TAG,"mSelectedItem=" +mSelectedItem); holder.imageView.setImageDrawable(mFilterDrawableList.get(position)); if(position == mSelectedItem) { holder.imageView.requestFocus(); holder.imageView.setSelected(true); Log.e(TAG,"requesting focus="); //holder.mBgView.setBackgroundResource(R.drawable.button_box_hil); } else { holder.imageView.setSelected(false); //holder.mBgView.setBackgroundResource(0); } } @Override public void onAttachedToRecyclerView(final RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); mRecyclerView = recyclerView; } @Override public void onItemSelected(AdapterView<?> pParent, View pView, int pPosition, long pId) { Log.d(TAG,"onItemSelected " + pPosition); } @Override public int getItemCount() { return mFilterDrawableList.size(); } @Override public void onNothingSelected(AdapterView<?> arg0) { Log.e(TAG,"onNothingSelected"); } @Override public void onAnimationCancel(Animator pAnimator) { } @Override public void onAnimationEnd(Animator pAnimator) { } @Override public void onAnimationRepeat(Animator pAnimator) { } @Override public void onAnimationStart(Animator pAnimator) { } public void moveFocus(int pDirection) { int lNextSelect = mSelectedItem + pDirection; if (lNextSelect >= 0 && lNextSelect < getItemCount()) { //notifyItemChanged(mSelectedItem); mSelectedItem = lNextSelect; //notifyItemChanged(mSelectedItem); mRecyclerView.smoothScrollToPosition(mSelectedItem); if(mRecyclerView.getChildAt(mSelectedItem) != null) { //mRecyclerView.getChildAt(mSelectedItem).requestFocus(); } } else { return; } setNavigatorText(); setCurrentSelection(mSelectedItem); int lSelectedList = mCursorIdxList.get(mSelectedItem); mCacheManager.setCurrentListIdx(lSelectedList); mListUtil.selectList(lSelectedList); mNtfHandler.notifyAllObservers(EventID.CH_LIST_REFRESH,null); } public void refresh() { mRecyclerView.smoothScrollToPosition(mSelectedItem); int lCurrentList = mCacheManager.getCurrentListIdx(); int lNewSelection = mCursorIdxList.indexOf((Integer)lCurrentList); Log.d(TAG,"refresh: old selection - "+ mSelectedItem + "new selection - " + lNewSelection); if(mSelectedItem != lNewSelection) { //notifyItemChanged(mSelectedItem); mSelectedItem = lNewSelection; //notifyItemChanged(mSelectedItem); if(mRecyclerView.getChildAt(mSelectedItem) != null) { mRecyclerView.getChildAt(mSelectedItem).requestFocus(); } setNavigatorText(); setCurrentSelection(mSelectedItem); } } } 。超类:

Optional

示例子类:

public abstract class PlanetaryBody {

    /**
     * @return If this PlanetaryBody is a Star, then an Optional containing this as a Star.
     * Otherwise an empty Optional.
     */
    public Optional<Star> asStar() {
        return Optional.empty();
    }

    public Optional<Planet> asPlanet() {
        return Optional.empty();
    }

    // Similar methods for other subclasses

}

以上允许我们使用这样的类:

public class Star extends PlanetaryBody {

    public void shineBrightly() {
        // ...
    }

    @Override
    public Optional<Star> asStar() {
        return Optional.of(this);
    }

}

优点:

  • 灵活,您可以在适当的位置均匀地处理行星体,并在需要时轻松转换为混凝土类型。
  • 不使用 PlanetaryBody body = // ... body.asStar().ifPresent(s -> { // body is a star s.shineBrightly(); }); 或其他皱眉结构。
  • 输入安全。

缺点:

  • 课程紧密耦合。超类需要知道它的子类。每次添加子类时都需要修改超类。
  • 它可能被认为有点罗嗦,你需要在所有子类中获得非常相似的代码。

编辑:我正在使用Java 8中引入的instanceof类。主要(仅?)的目的是从方法中返回null的安全值。当一个方法可能返回某些内容或者什么都没有时 - 例如Optional可能会发生 - 旧的方法是让它返回一个可能是asStar的引用。当调用者不知道返回值可能是null或者忘记检查时,这会产生NullPointerException s。经常发生。您可能会争辩说,在这种情况下,这不是一个很大的风险,因此我们可以将null作为thisStar返回。

使用null方法永远不需要(也绝不能)返回Optional。相反,它会返回一个null,其中包含或不包含值。我通常使用Optional从方法获得的方法是通过其Optional方法,如上所示。我将lambda(或方法引用)传递给它,并且只有存在值时才执行内部代码。因此,在我的代码中isPresent是对sStar的引用,并且保证为非空(否则代码将不会被执行)。

Java 9引入了变体Optional,它还将在ifPresentOrElse为空的情况下执行代码块。

您当然可以在互联网上阅读有关Optional的更多信息。我变得非常喜欢它。如果您可以在谈话的背景下阅读,我推荐下面链接中的幻灯片 - 否则,YouTube上也可以提供该演讲。需要注意的一点是:如果您在某个地方读到应该使用方法OptionalOptional.isPresent,请不要相信,您很少应该这样做(请注意Optional.get与s之间的区别isPresent使用f,两种方法都存在,请像我一样使用后者。

不使用ifPresent 的变体(未经测试)。在超类中:

Optional

在具体的子类中:

    public Star asStar() {
        return null;
    }

使用方法:

    public Star asStar() {
        return this;
    }

链接: Slide deck Optional: The Mother of All Bikesheds by Stuart Marks, Oracle