我在服务上有这两种方法:
public Offer GetOffer(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entities.Offer offerEntity = _db.Offers.FirstOrDefault(offer => offer.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using (IDocumentSession session = store.OpenSession())
{
Translation.Offer translatedOffer = session.LuceneQuery<Translation.Offer>(Website.RavenDbSettings.Indexes.Offers)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(offer => offer.Id)
.FirstOrDefault();
var offerPOCO = Mapper.DynamicMap<Translation.Offer, Offer>(translatedOffer);
offerPOCO.Id = offerEntity.Id;
return offerPOCO;
}
}
return Mapper.Map<Entities.Offer, Offer>(offerEntity);
}
和
public Hotel GetHotel(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entities.Hotel hotelEntity = _db.Hotels.FirstOrDefault(hotel => hotel.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
Translation.Hotel translatedHotel = session.LuceneQuery<Translation.Hotel>(Website.RavenDbSettings.Indexes.Hotels)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(hotel => hotel.Id)
.FirstOrDefault();
Hotel hotelPOCO = Mapper.DynamicMap<Translation.Hotel, Hotel>(translatedHotel);
hotelPOCO.Id = hotelEntity.Id;
return hotelPOCO;
}
}
return Mapper.Map<Entities.Hotel, Hotel>(hotelEntity);
}
它们在大多数方面完全相同:它们采用相同的参数,构建相同的查询并进行相同的操作,唯一不同的是它们使用和输出的对象类型。除了构建一个生成Where()参数字符串的方法之外,我想不出任何方法可以将大部分(或全部)此代码合并到一个方法中,然后从GetOffer()和GetHotel()中调用它方法,因为我最终会得到更多这样的两个。
非常感谢任何建议。
编辑:添加解决方案,如果另一个可怜的灵魂遇到这个问题,他/她可以有一个起点:
private TReturn GetObject<TReturn, TEntity, TTranslation>(int id, string languageCode, string ravenDbIndex) where TEntity:EntityObject
where TTranslation:Translation.BaseTranslationObject
where TReturn:BasePOCO
{
// TODO Run more tests through the profiler
var entities = _db.CreateObjectSet<TEntity>();
var entityKey = new EntityKey(_db.DefaultContainerName + "." + entities.EntitySet.Name, "Id", id); // Sticking to the Id convention for the primary key
TEntity entity = (TEntity)_db.GetObjectByKey(entityKey);
if(languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
TTranslation translatedObject = session.LuceneQuery<TTranslation>(ravenDbIndex)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(translation => translation.Id)
.FirstOrDefault();
TReturn poco = Mapper.DynamicMap<TTranslation, TReturn>(translatedObject);
poco.Id = id;
return poco;
}
}
return Mapper.Map<TEntity, TReturn>(entity);
}
然后我打电话给:
GetObject<Hotel, Entities.Hotel, Translation.Hotel>(id, languageCode, Website.RavenDbSettings.Indexes.Hotels);
每当我需要酒店时。
感谢大家的回复,他们从中学到了很多。
答案 0 :(得分:6)
看起来您可以将其重构为通用方法。类似的东西(我正在对重构一些方法调用的能力做出一些假设,等等。但希望你能得到这个想法)
public T Get<T>(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entity<T> entity = _db<T>.FirstOrDefault(entity => entity.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
Translation<T> translatedEntity = session.LuceneQuery<Translation<T>>(Website.RavenDbSettings.Indexes.Entities<T>)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(entity=> entity.Id)
.FirstOrDefault();
T POCO = Mapper.DynamicMap<Translation<T>, T>(translatedEntity);
POCO.Id = entity.Id;
return POCO;
}
}
return Mapper.Map<Entities<T>, T>(Entity);
}
答案 1 :(得分:1)
建议保持原样。他们返回不同的类型,并保证不同的方法。我的直觉是它属于Do One Thing - Single Responsibility Principle。
确实他们在完成工作时实施了相同的策略,但我建议如果你将它们合并/重构为一个会比收益更令人困惑。
考虑业务逻辑变化的可能性。一个人会比另一个人更不稳定吗?实现此功能是否与GetFlights()
和GetCarRentals()
相同?
我意识到,在使代码相同,并且可能在方法之间复制/粘贴/调整代码时,您会感觉到可以减少代码行,并且不要重复自己。我同样重视SRP和DRY,但在这种情况下,我宁愿为Offer
,Hotel
等每个实体阅读和维护不同的方法。
答案 2 :(得分:0)
在这样的情况下,我将变量项隔离并将它们放入sig中,如果sig变得太大而难以/难以调用,那么看看泛型是否可以使这更简单,或者是否可以将部分考虑到其类型中在这种情况下我会想到什么。如果在通话中填写一个动作或功能也可以提供帮助,这可能是您可以打电话的地方:
GetDalObject(db => db.Hotels.FirstOrDefault(hotel => hotel.Id == id), ...
然后你可以在酒店或优惠等之间的通话中交换它,但在你的情况下,我不知道这有多大可以帮助,因为我认为sig真的会变得讨厌,所以我会看看变量部分并在Offer类型和酒店类型中实现它们,您可以通过界面访问它们,然后将Offer / Hotel类交给此方法。
public interface ICommonDalObject
{
public string LuceneQueryString { get; }
public ITranslation GetTranslation();
}