el asunto no es raro es muy comun solo que a muchos no le interesa o les da igual
aqui una propuesta de solucion no todos lo hacen igual y muchos tienes diferentes opiniones
fijate en el detalle que si quiero cambiar de base de datos en mememoria por una base de datos real tendrias que reemplasar AccesoADatosEnMemoriaProducto() cualquier clase que implemente AccesoADatosProducto 
public class Main {
	public static void main(String arg[]) {
		AccesoADatosProducto accesoADatosProducto = new AccesoADatosEnMemoriaProducto();
		accesoADatosProducto
				.agregarProducto(new Producto(1, "computadora", 10));
		accesoADatosProducto.agregarProducto(new Producto(2, "telivisor", 20));
		accesoADatosProducto.agregarProducto(new Producto(3, "monitor", 30));
		for (Producto producto : accesoADatosProducto.listarProducots()) {
			System.out.println(producto);
		}
	}
}
import java.util.List;
[code]
import java.util.List;
public interface AccesoADatosProducto {
	public abstract void agregarProducto(Producto Producto);
	public abstract void eliminarProducto(int codigo);
	public abstract void modificarProducto(int codigo, Producto nuevoProducto);
	public abstract Producto obtenProducto(int codigo);
	public abstract List<Producto> listarProducots();
}
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
public class AccesoADatosEnMemoriaProducto implements AccesoADatosProducto {
	private Hashtable<Integer, Producto> productos = new Hashtable<Integer, Producto>();
	@Override
	public void agregarProducto(Producto producto) {
		productos.put(producto.getCodigo(), producto);
	}
	@Override
	public void eliminarProducto(int codigo) {
		productos.remove(codigo);
	}
	@Override
	public void modificarProducto(int codigo, Producto nuevoProducto) {
		if (productos.containsKey(codigo)) {
			throw new RuntimeException("bruto no se puedo ingresar el producto"
					+ nuevoProducto
					+ "devido a que no existe un producto con el mismo codigo");
		}
		productos.put(codigo, nuevoProducto);
	}
	@Override
	public Producto obtenProducto(int codigo) {
		return productos.get(codigo);
	}
	@Override
	public List<Producto> listarProducots() {
		List<Producto> list = new ArrayList<Producto>();
		Enumeration<Producto> enumproduct = productos.elements();
		while (enumproduct.hasMoreElements()) {
			Producto producto = (Producto) enumproduct.nextElement();
			list.add(producto);
		}
		return list;
	}
}
public class MySqlAccesoADatosProducto implements AccesoADatosProducto {
	@Override
	public void agregarProducto(Producto Producto) {
	}
	@Override
	public void eliminarProducto(int codigo) {
	}
	@Override
	public void modificarProducto(int codigo, Producto nuevoProducto) {
	}
	@Override
	public List<Producto> listarProducots() {
		return null;
	}
	@Override
	public Producto obtenProducto(int codigo) {
		return null;
	}
}
public class Producto {
	private int codigo;
	private String nombre;
	private double precio;
	public Producto(int codigo, String nombre, double precio) {
		this.codigo = codigo;
		this.nombre = nombre;
		this.precio = precio;
	}
	public int getCodigo() {
		return codigo;
	}
	public void setCodigo(int codigo) {
		this.codigo = codigo;
	}
	public String getNombre() {
		return nombre;
	}
	public void setNombre(String nombre) {
		this.nombre = nombre;
	}
	public double getPrecio() {
		return precio;
	}
	public void setPrecio(double precio) {
		this.precio = precio;
	}
	@Override
	public String toString() {
		return codigo + " " + nombre + " " + precio;
	}
}
felizmente te diste cuenta a tiempo eso se puede hacer de muchas maneras solo es cuestión de jugar con las interfases y clases abstractas las soluciones mas comunes y que se la saben todo el mundo se llaman patrones de diseño 
el patron de diseño para para cambiar la fuente de datos por cualquiera se llama dao es usado en combinacion de otros patrones como el factory(algunos les gusta abstracfactory) y el singleton
[/code]