我正在尝试实现存储库模式,但是当实体具有不同类型的ID时,我不明白它怎么可能。目前,我必须回退到使用对象,而我真的想使用存储库所持有实体的ID的特定类型。
const path = require('path');
const webpack = require('webpack');
const pkg = require('./package.json');
const fs = require('fs');
const banner = `${pkg.name} - ${pkg.version} - (c) 2017 - ${pkg.author} - ${pkg.homepage} \n\n ${fs.readFileSync('LICENSE').toString()}`;
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './awsdk_module/lib/'),
filename: 'awsdk.js',
library: 'awsdk',
libraryTarget: 'umd',
umdNamedDefine: true,
},
devtool: 'source-map',
module: {
noParse: [/dtrace-provider$/, /safe-json-stringify$/, /mv/],
rules: [
{
test: /\.js$/,
include: path.join(__dirname, './src/awsdk'),
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.js$/,
include: path.join(__dirname, './specs'),
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
node: {
console: false,
fs: 'empty',
net: 'empty',
module: 'empty',
tls: 'empty',
},
devServer: {
contentBase: path.join(__dirname, './specs'),
inline: true,
port: 8081,
},
plugins: [
new webpack.BannerPlugin(banner),
],
};
我也尝试过类似的事情:
interface IEntity
{
object GetId();
}
class Foo : IEntity
{
private string id;
public Foo(string id)
{
this.id = id;
}
public object GetId()
{
return id;
}
}
class Bar : IEntity
{
private int id;
public Bar(int id)
{
this.id = id;
}
public object GetId()
{
return id;
}
}
class Repository<T> where T : IEntity
{
private Dictionary<object, T> entities = new Dictionary<object, T>();
public IEnumerable<T> List => entities.Values.AsEnumerable();
public void Add(T entity)
{
entities.Add(entity.GetId(), entity);
}
public T Get(object id)
{
return entities[id];
}
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo("0");
var bar = new Bar(0);
var fooRepo = new Repository<Foo>();
fooRepo.Add(foo);
fooRepo.Get(foo.GetId());
var barRepo = new Repository<Bar>();
barRepo.Add(bar);
barRepo.Get(bar.GetId());
}
}
答案 0 :(得分:1)
您可以将密钥的通用类型添加到IEntity
。例如,
interface IEntity<TId>
{
TId GetId();
}
class Foo : IEntity<string>
{
private string id;
public Foo(string id)
{
this.id = id;
}
public string GetId()
{
return id;
}
}
class Repository<TEntity, TId> where TEntity : IEntity<TId>
{
private Dictionary<TId, TEntity> entities = new Dictionary<TId, TEntity>();
public void Add(TEntity entity)
{
entities.Add(entity.GetId(), entity);
}
public TEntity Get(TId id)
{
return entities[id];
}
}
答案 1 :(得分:0)
Joel的解决方案可以扩展为允许变化。通用集合以同样的方式实现IEnumerable
和IEnumerable<T>
。
实体
interface IEntity
{
object GetId();
}
interface IEntity<TId> : IEntity
{
new TId GetId();
}
abstract class EntityBase<TId> : IEntity<TId>
{
protected TId id;
protected EntityBase(TId id)
{
this.id = id;
}
public TId GetId() => id;
object IEntity.GetId() => GetId();
}
存储库
abstract class Repository
{
protected Dictionary<object, IEntity> entities;
protected Repository()
{
entities = new Dictionary<object, IEntity>();
}
public virtual void Add(IEntity entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
entities.Add(entity.GetId(), entity);
}
public virtual IEntity Get(object id)
{
if (id == null) throw new ArgumentNullException(nameof(id));
return entities[id];
}
}
abstract class Repository<TId, TEntity> : Repository
where TEntity : class, IEntity<TId>
{
protected Repository() : base() { }
public override void Add(IEntity entity)
{
Add((TEntity)entity);
}
public override IEntity Get(object id)
{
return Get((TId)id);
}
public void Add(TEntity entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
entities.Add(entity.GetId(), entity);
}
public TEntity Get(TId id)
{
if (id == null) throw new ArgumentNullException(nameof(id));
return (TEntity)entities[id];
}
}
用例
class Foo : EntityBase<string>
{
public Foo(string id) : base(id) { }
}
class Bar : EntityBase<int>
{
public Bar(int id) : base(id) { }
}
class FooRepository : Repository<string, Foo>
{
public FooRepository() { }
}
class BarRepository : Repository<int, Bar>
{
public BarRepository() { }
}
测试
[TestMethod]
public void IEntitySupport()
{
// use IEntity and object
IEntity bar = new Bar(1);
Repository barRepository = new BarRepository();
barRepository.Add(bar);
var bar2 = barRepository.Get((object)1);
Assert.AreSame(bar, bar2);
}
[TestMethod]
public void TEntitySupport()
{
// use TEntity and TId
var foo = new Foo("a");
var fooRepository = new FooRepository();
fooRepository.Add(foo);
var foo2 = fooRepository.Get("a");
Assert.AreSame(foo, foo2);
}