首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >设计图案策略中的菱形算子问题

设计图案策略中的菱形算子问题
EN

Stack Overflow用户
提问于 2022-08-27 21:46:24
回答 2查看 80关注 0票数 0

关于钻石操作符和Java设计模式策略的小问题,请。

我想执行一项非常具体的要求:

  • 有一些对象需要存储(在我的示例中称为MyThingToStore)
  • 其要求是以不同的数据结构存储它们,以便进行比较。

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

守则如下:

代码语言:javascript
运行
复制
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!
    }
}

这是很好的工作,非常高兴,特别是解决了“易于改变数据结构来做实际存储”的要求。

(顺便问一下,如果有更好的办法,请告诉我!)

现在,在网上查看不同策略模式的实现,我看到了这个钻石操作符,我很难理解它:

代码语言:javascript
运行
复制
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!
    }
}

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

我的问题是:没有钻石操作符的版本和钻石操作符的版本有什么不同?

这两种方法中哪一种“更好”,为什么?

虽然这个问题似乎“含糊不清”,但我相信有理由作出更好的选择。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-08-27 22:28:08

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

让我们把它命名为T作为类型。在本例中,T只是一个占位符,用来表示StorageStrategy可以处理的对象类型。

代码语言:javascript
运行
复制
public interface StorageStrategy<T> {
    void addToStore(T myThingToStore);
    int getSize();
}

例如。

代码语言:javascript
运行
复制
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实现,以便还包括类型参数。

代码语言:javascript
运行
复制
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的类型参数。

代码语言:javascript
运行
复制
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。这是否是你想要的,取决于你自己。

票数 2
EN

Stack Overflow用户

发布于 2022-08-27 22:17:12

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

也就是说,它不是实际的类型,而是类型的占位符,比如T。通常的惯例是使用单字母的泛型类型变量(TUR等),否则在这种情况下可能会让人感到困惑。

注意到了类声明中的,如:

代码语言:javascript
运行
复制
public class StorageUsingArrayListStrategy 
    implements StorageStrategy<MyThingToStore>

MyThingToStore不再是一个类型变量,而是类MyThingToStore的名称,因为在这种情况下,参数化接口是由一个非参数化类实现的(也就是说,编译所知道的实际类型将被提供)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73514616

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档