合并这两种非常相似的方法

时间:2010-08-09 18:28:17

标签: c# asp.net

我在服务上有这两种方法:

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);

每当我需要酒店时。

感谢大家的回复,他们从中学到了很多。

3 个答案:

答案 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,但在这种情况下,我宁愿为OfferHotel等每个实体阅读和维护不同的方法。

答案 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();
}