Budowanie menu na podstawie rekursywnej struktury

0

Cześć. Buduję sobie klasę Menu, która zawiera guziki. Guziki mogą być abstrakcyjne, czyli nie odpowiadające żadnemu obiektowi i realne czyli odpowiadające jakiemuś obiektowi. Robie tak dlatego że chcę żeby moje menu było ogólne i żeby dało się go użyć nie tylko z jednym typem struktury danych.

Mój problem polega na tym że trochę zaplątałem się w implementacji. Nie mam za dużego doświadczenia z interfejsami. Oto mój kod>

Menu:

package model;

import java.util.ArrayList;
import java.util.List;

public class Menu {
	private List<Button> buttons = new ArrayList<Button>();
	private int numberOfButtons = 0;
	private int currentButton;
	private int topButton;
	private int maxButtonsPage;
	private Button parent;
	private List<NamedObject> objects = null;
	
	//real menu with all real buttons
	public Menu(List<NamedObject> objects, int maxButtons, Button parent){
		this.numberOfButtons = objects.size();
		this.currentButton = 0;
		this.topButton = 0;
		this.maxButtonsPage = maxButtons;
		this.parent = parent;
		this.objects = objects;
		for(int i = 0; i < objects.size();i++){
			buttons.add(new Button(objects.get(i),this));
		}
	}
	public Menu(Button parent){
		this.numberOfButtons = 0;
		this.currentButton = -1;
		this.parent = parent;
		this.topButton = -1;
		buttons = null;
	}
	//abstract menu with all abstract buttons
	public Menu(List<String> names, List<Behavior> behaviors, Button parent){
		this.numberOfButtons = names.size();
		this.currentButton = 0;
		this.topButton = 0;
		this.parent = parent;
		for(int i = 0; i < names.size();i++){
			buttons.add(new Button(names.get(i), behaviors.get(i), this));
		}
	}
	public Button getParent(){
		return this.parent;
	}
	public void addRealButton(NamedObject object){
		if(this.buttons == null){
			this.currentButton = 0;
			this.topButton = 0;
		}
		this.buttons.add(new Button(object, this));
	}
	public void addAbstractButton(String name, Behavior behavior){
		if(this.buttons == null){
			this.currentButton = 0;
			this.topButton = 0;
		}
		this.buttons.add(new Button(name, behavior, this));
	}
	public int getCurButton(){
		return this.currentButton;
	}
	public void setCurButton(int button){
		this.currentButton = button;
	}
	public Button getButton(int button){
		return buttons.get(button);
	}
	public int getNoButtons(){
		return this.numberOfButtons;
	}
	public List<Button> getButtons(){
		return this.buttons;
	}
	public void setButtons(List<Button> buttons){
		this.buttons = buttons;
		this.numberOfButtons = buttons.size();
	}
	public int getTopButton(){
		return this.topButton;
	}
	public void setTopButton(int number){
		this.topButton = number;
	}
	public void setSubMenu(int button, Menu menu){
		this.buttons.get(button).setSubMenu(menu);
	}
	public Menu getSubMenu(int button){
		updateMenu();
		return this.buttons.get(button).getSubMenu();
	}
	public void advanceCurButton(){
		if (this.topButton + maxButtonsPage - 1== this.currentButton && this.currentButton < this.numberOfButtons - 1)
			++this.topButton;
		if (this.currentButton != this.numberOfButtons-1)
			++this.currentButton;
	}
	public void retardCurButton(){
		if (this.currentButton == this.topButton && this.currentButton != 0)
			--this.topButton;
		if (this.currentButton != 0)
			--this.currentButton;
	}
	public Menu getSelSubMenu(){
		return this.buttons.get(this.currentButton).getSubMenu();
	}
	public Button getSelButton(){
		return this.buttons.get(this.currentButton);
	}
	private void updateMenu(){
		buttons = null;
		for(int i = 0; i < objects.size();i++){
			buttons.add(new Button(objects.get(i),this));
		}
	}
}
 

Jak zapewne widać w kodzie, jest tam Interface Behavior. Jets on po to żeby program wiedział co robić kiedy kliknąć na abstrakcyjny guzik. W wypadku realnego guzika chcę tylko wejść w podmenu guzika, lub nic nie robić jeśli takowego nie ma.

package model;

import java.util.List;

public class Button {
	private Menu submenu = null;
	private String name = "";
	private boolean hasSubMenu;
	private boolean hasCustomBehavior = false;
	private NamedObject object = null;
	private Menu parent;
	private Behavior behavior;
	
	//2 real button constructors
	public Button(NamedObject object, Menu menu, Menu parent){
		this.submenu = menu;
		this.hasSubMenu = true;
		this.parent = parent;
		this.name = object.getName();
		this.object = object;
	}
	public Button(NamedObject object, Menu parent){
		this.hasSubMenu = false;
		this.parent = parent;
		this.name = object.getName();
		this.object = object;
	}
	//one abstract button constructors
	public Button(String name, Behavior behavior, Menu parent){
		this.hasCustomBehavior = true;
		this.name = name;
		this.behavior = behavior;
	}
	public Menu getParent(){
		return this.parent;
	}
	public void setName(String newName){
		this.name = newName;
	}
	public String getName(){
		return this.name;
	}
	public Menu getSubMenu(){
		return this.submenu;
	}
	public void setSubMenu(Menu submenu){
		this.submenu = submenu;
		this.hasSubMenu = true;
	}
	public boolean hasSubMenu(){
		return this.hasSubMenu;
	}
	public boolean hasCustomBehavior() {
		return this.hasCustomBehavior;
	}
	public void setCustomBehavior(Behavior behavior) {
		this.hasCustomBehavior = true;
		this.behavior = behavior;
	}
	public Behavior getBehavior(){
		return this.behavior;
	}
	public Object getObject(){
		return this.object;
	}
//tutaj mam problemy
	public void setRecursiveObjectMenu(RecursiveNamedObject obj){
		for (int i = 0; i < obj.getNumberOfChildren(); i++){
			this.submenu = new Menu(obj.getChildren(), 6, this);
			setRecursiveObjectMenu((RecursiveNamedObject) obj.getChild(i));
		}
	}
}
 

W ostatniej metodzie próbuję stworzyć całe menu(wliczając pod menu i pod pod menu itd.). RecursiveNamedObject to interfejs>

package model;

import java.util.List;

public interface RecursiveNamedObject {
	public Object getChild(int index);
	public int getNumberOfChildren();
	public String getName();
	public List<Object> getChildren();
}
 

Mój problem polega na tym że jak mam interfejs który ma metodę na przykład getChildren która ma zwracać listę obiektów, to nie moge z góry zakładać jakiego typu będzie ta lista, czy List<Directory>, czy List<Cubes>, dlatego wpisałem List<Object>. Ale teraz w klasach które implementują ten interfejs, chciałbym metodą getChildren zwracać rózne typy list, na przykład List<Directory>, czyego niestety zrobić nie mogę.

Mam jeszcze kilka problemów, ale nie umiem ich wytłumaczyć, myślę że będziecie wiedzieć o co chodzi jak zobaczycie kod.

0

Okej właśnie mi się zachciało trochę programować więc wróciłem do problemu. Moje pytanie mogło być trochę pogmatwane więc postanowiłem zrobić kilka zmian w kodzie i napisać je od nowa.

Mam działający program, który dzięki klasie DirectoryReader robi listę katalogów i plików:

public class Directory {
	private List<Directory> subdirs = new ArrayList<Directory>();
	private String name;
	private boolean isFile = true;
	
	public Directory(String name, List<Directory> subdirs, boolean isFile){
		this.setSubdirs(subdirs);
		this.setName(name);
		this.setFile(isFile);
	}
	public boolean isEmpty(){
		if (subdirs == null)
			return true;
		if (subdirs.size() == 0)
			return true;
		return false;
	}
//pominalem kilka getterow i setterow.
}
 
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class DirectoryReader {	
	public DirectoryReader(){}
	private List<Directory> readDirectories(int depth, File file){
		//depth == -1 if all directories should be listed
		if (depth != 0 && !file.isFile()){
			File[] subfiles = file.listFiles();
			List<Directory> dirs = new ArrayList<Directory>();
			for(File subfile : subfiles)
				dirs.add(new Directory(subfile.getName(), readDirectories(depth - 1, subfile), subfile.isFile()));
			return dirs;
		}
		return null;
	}
	public Directory readDirectories(int depth, String path){
		File file = new File(path);
		return new Directory(file.getName(), readDirectories(depth, file), file.isFile());
	}
}

 

Wszystko działa pięknie. Teraz tworzę menu na podstawie wcześniej stworzej struktury Directory:

	public Menu(Directory directory, Button parent){
		this.setParent(parent);
		for(Directory dir : directory.getSubdirs())
			if (!dir.isEmpty() || dir.isFile()){
				this.numberOfButtons++;
				this.currentButton = 0;
				this.topButton = 0;
				Button button = new Button(dir.getName(), this);
				if (!dir.isFile())
					button.setSubMenu(new Menu(dir, button));
				this.buttons.add(button);
			}
	}
 

I wszystko działa znakomicie. Moje pytanie, jak zrobić żeby konstruktor Menu mógł używać innych typów niż Directory?

1 użytkowników online, w tym zalogowanych: 0, gości: 1