Your code only hides a dependency if Product is abstract, and "Product B" is actually an instance of some derivative of that class, like "MobileProduct",
if Product is not abstract you only hide the implementation of "Product" and not it's existence.
Or if the factory is the thing that is abstract, then you actually hide the many ways you could produce a Product. For instance if you have a "SqlProductFactory", or "InMemoryProductFactory". Then you hide the dependency on how the products are stored, created, or their origin.
Weather or not factories are good for design or not, highly depends on your problem, and how it is solved. For instance if you are building a big API or library it may make sense to hide some dependencies that the consumer doesn't need to know about. But if you only need to solve "Hello World" or "FizzBuzz" there isn't really need for a class - let alone a factory.
So to answer your questions, does your code hide the dependency? Is it good design? Well in both cases it depends on the problem at hand.
EnemyBase {
int Hitpoints;
int Damage;
void Speak();
}
EasyEnemy : EnemyBase {
public int Hitpoints = 100;
public int Damage = 20;
private string Name = "EZGuy";
public void Speak(){
print this.Name + ": I shall destroy you!";
}
}
HardEnemy : EnemyBase {
public int Hitpoints = 200;
public int Damage = 40;
private string Name = "Da hard1";
public void Speak(){
print this.Name + ": Your days are numbered!";
}{
}
EnemyFactory {
private int EnemiesProduced = 0;
public EnemyBase getEnemy(){
if(IsOdd(++this.EnemiesProduced)){
return new EasyEnemy();
} else {
return new HardEnemy();
}
}
}
Game {
EnemyFactory enemies;
public Game(EnemyFactory factory){
enemies = factory;
}
public void Start(){
EnemyBase e = factory.getEnemy();
}
}
Here Game doesn't know anything about HardEnemy or EasyEnemy, it only cares about getting an EnemyBase. It also only knows about the the two public fields, and the speak method that EnemyBase class provides. Which may or may not be a good thing. For instance here it enables us to change the implementations of enemies, without having to change the Game, this let's us focus on developing enemies and test how they affect the game - without having to give any attention to game. So it can be a really good thing, that let's you develop things faster, maybe between teams, or future proof your solution. But it may also be a totally unnecessary layer of complexity -
So to conclude :) It really depends :) (Pun may or may not be intended)