dragon_9000
2019-09-04 15:47
浏览 114
已采纳

Golang在私有访问结构中嵌入接口

I want to replicate the following Java code in Golang in the most idiomatic way possible:

public class Handler {

    private Storage storage;
    private Mapper mapper;

    public Handler(Storage storage, Mapper mapper) {
        this.storage = storage;
        this.mapper = mapper;
    }

    public void handleKey(String k) {
        storage.put(k, mapper.map(k));
    }

}

interface Storage {
    public void put(String k, String v);
    public String get(String k);
}

@FunctionalInterface
interface Mapper {
    public String map(String a);
}

private static class InMemoryStorage implements Storage {
    private Map<String, String> table;

    public InMemoryStorage() {
        table = new HashMap<>();
    }

    public void put(String k, String v) {
        table.put(k, v);
    }

    public String get(String k) {
        return table.get(k);
    }
}

Handler class only exposes the method handleKey. The behaviour of this class is parametrized by passing different concrete Storage and Mapper implementations.

After reading Effective Go - Embedding, I thought this would be a good use of embedding interfaces intro structs. But I can't figure out how to avoid exposing the embedded interfaces' methods to Handler users. I can do something like

type Handler struct {
    store  Storage
    mapper Mapper
}

func (h Handler) Handle(k string) {
    h.store.Put(k, h.mapper.Map(k))
}

type Storage interface {
    Put(k string, v string)
    Get(k string) string
}

type Mapper interface {
    Map(k string) string
}

type inMemoryStorage {
    table map[string]string
}

func NewInMemoryStorage() Storage {
    return &inMemoryStore{table: make(map[string]string)}
}

but then I cannot pass concrete implementations to the Handler (creating struct literal) because store and mapper are unexported. And I do not want to create factory methods for each possible combination... Any suggestions?

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dongmei9961 2019-09-04 15:58
    已采纳

    Those are not embedded; embedding has a specific meaning in Go, as outlined in the spec, and as explained in the Effective Go section you linked to. It refers to unnamed fields, whose fields and methods are accessible implicitly from their containing type. Your fields are named, not embedded.

    That said, your two struct fields, store and mapper, are not exported, so they will not be exposed to any user outside the package in which Handler is defined; you seem to already have your desired behavior in that regard.

    I'm not sure what you mean when you say you would have to "create factory methods for each possible combination" - I don't see any reason that would be necessary. You need only one factory method:

    func NewHandler(s Storage, m Mapper) Handler {
        return Handler{store: s, mapper: m}
    }
    

    Which could be used with any combination of implementations of Storage and Mapper by passing appropriate values to the function.

    已采纳该答案
    打赏 评论

相关推荐 更多相似问题