关于设计模式策略的菱形运算符的问题



关于Java的菱形运算符和设计模式策略的小问题。

我想实现一个非常具体的要求:

  • 有一些对象要存储(在我的示例中称为MyThingToStore(

  • 并且要求将它们与不同类型的数据结构一起存储以便进行比较。

因此,我尝试了一种策略模式,其中每种策略都是不同的存储方式,我认为这种模式非常可爱。

代码如下:


public class MyThingToStore {
private final String name;
public MyThingToStore(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyThingToStore that = (MyThingToStore) o;
return Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public String toString() {
return "MyThingToStore{" +
"name='" + name + ''' +
'}';
}
}
public class MyStorage {
private final StorageStrategy storageStrategy;
public MyStorage(StorageStrategy storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
public interface StorageStrategy {
void addToStore(MyThingToStore myThingToStore);
int getSize();
}

public class StorageUsingArrayListStrategy implements StorageStrategy {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
@Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
@Override
public int getSize() {
return storeUsingArrayList.size();
}
}

public class StorageUsingHashSetStrategy implements StorageStrategy{
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
@Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
@Override
public int getSize() {
return storeUsingHashSet.size();
}
}

public class Main {
public static void main(String[] args) {
final StorageStrategy storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}

而且这个工作很好,很开心,特别是满足了";易于改变数据结构以进行实际存储";。

(顺便说一句,附带问题,如果有更好的方法,请告诉我!(

现在,在网上查看策略模式的不同实现,我看到了一个我很难理解的菱形运算符:


MyThingToStore stays the same.

public class MyStorage {
private final StorageStrategy<MyThingToStore> storageStrategy; //note the diamond here
public MyStorage(StorageStrategy<MyThingToStore> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
@Override
public String toString() {
return "MyStorage{" +
"storageStrategy=" + storageStrategy +
'}';
}
}

public interface StorageStrategy<MyThingToStore> {
//note the diamond, and it will be colored differently in IDEs
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy<MyThingToStore> {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
@Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
@Override
public int getSize() {
return storeUsingArrayList.size();
}
}

public class StorageUsingHashSetStrategy implements StorageStrategy<MyThingToStore> {
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
@Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
@Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy<MyThingToStore> storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}

而且两个版本都会产生同样好的结果,也能够满足要求。

我的问题是:请问没有菱形运算符的版本和有菱形运算符的版有什么区别?

这两种方式中哪一种是";"更好";为什么?

虽然这个问题可能看起来是";太模糊";,我相信有理由做出更好的选择。

我认为混淆来自于您在第二个示例中如何为StorageStrategy命名类型参数。

让我们将其命名为T以表示类型。在这种情况下,T只是一个占位符,用来表示StorageStrategy可以使用什么类型的对象。

public interface StorageStrategy<T> {
void addToStore(T myThingToStore);
int getSize();
}

例如

StorageStrategy<MyThingToStore> strategy1 = // Initialization 
StorageStrategy<String> strategy2 = // Initialization 
strategy1.addToStore(new MyThingToStore("Apple"));
// This works fine, because strategy2 accepts "String" instead of "MyThingToStore"
strategy2.addToStore("Apple");
// Last line doesn't work, because strategy1 can only handle objects of type "MyThingToStore"
strategy1.addToStore("Apple");

为了使其正常工作,您需要更改不同的StorageStrategy实现,使其也包含类型参数。

public class StorageUsingHashSetStrategy<T> implements StorageStrategy<T> {
private final Set<T> storeUsingHashSet = new HashSet<>();
@Override
public void addToStore(T myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
@Override
public int getSize() {
return storeUsingHashSet.size();
}
}

最后,你还想有一个MyStorage的类型参数

public class MyStorage<T> {
private final StorageStrategy<T> storageStrategy;
public MyStorage(StorageStrategy<T> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(T myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}

现在,您可以创建一个MyStorage,并可以使用它将基本上任何对象存储到其中,而不仅仅是MyThingToStore。这是否是你想要的,取决于你自己。

在接口StorageStrategy<MyThingToStore>声明的第二个代码示例中,MyThingToStore是一个类型变量。

也就是说,它不是实际的类型,只是一个类型的占位符,比如T。常见的约定是使用单字母通用类型变量(TUR等(,否则可能会像本例中那样令人困惑。

注意在类声明中,如:

public class StorageUsingArrayListStrategy 
implements StorageStrategy<MyThingToStore>

MyThingToStore不再是类型变量,而是类MyThingToStore的名称,因为在这种情况下,参数化接口是由非参数化类实现的(即,期望提供编译已知的实际类型(。

最新更新