隔离类仅由特定类实例化:最佳实践

时间:2014-10-08 13:49:18

标签: c# optimization

好的,我正在使用2层类:某个“经理”类,其任务是获取一个对象,链接所有附加到它的项目,然后将其返回给调用者,以及一个“数据”类。任务是根据特定请求调用数据库。

这是我工作方式的一个例子。这是一个“经理”课程:

public class CardManager
{
    private static readonly CardData mCardDAL = new CardData();

    public List<CardDisplay> ListCardsToShow(int _pageNumber, string _queryString, string _rarity, string _type, string _color, out int _totalCount)
    {
        List<CardDisplay> listToReturn = mCardDAL.ListCardsToShow(_pageNumber, _queryString, _rarity, _type, _color, out _totalCount);

        LinkListCardDisplayData(listToReturn);

        return listToReturn;
    }


    /// <summary>
    /// Method links the card set with each cards of the list.
    /// </summary>
    /// <param name="_listToReturn"></param>
    private static void LinkListCardDisplayData(IEnumerable<CardDisplay> _listToReturn)
    {
        try
        {
            foreach (CardDisplay item in _listToReturn)
            {
                LinkCardDisplayData(item);
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }

    private static void LinkCardDisplayData(CardDisplay _item)
    {
        _item.mMasterCardID = _item.mMasterCard.mCardID;

        ImagesManager.GetCardImages(_item);

        if (_item.mChildCard != null)
        {
            _item.mChildCardID = _item.mChildCard.mCardID;
        }
    }
}

这是一个“数据”类,即此事件中的CardData类:

public class CardData
{
    internal List<CardDisplay> ListCardsToShow(int _pageNumber, string _queryString, string _rarity, string _type, string _color, out int _totalCount)
    {
        using (DatabaseEntity db = new DatabaseEntity())
        {
            db.Database.Connection.Open();

            List<CARD> cardData;

            List<CardInfo> listCards;

            if (!String.IsNullOrWhiteSpace(_queryString))
            {
                var predicate = GetCardPredicate(_queryString);

                if (_rarity != "All")
                {
                    predicate = predicate.And(_item => _item.CARD_RARTY == _rarity);
                }

                if (_color != "All")
                {
                    predicate = predicate.And(
                            _item => _item.CARD_MANA_COST.Contains(_color) || _item.CARD_COLOR.Contains(_color));
                }

                if (_type != "All")
                {
                    predicate = predicate.And(_item => _item.CARD_TYPE.Contains(_type));
                }

                var cardQry = from c in db.CARD.AsExpandable().Where(predicate)
                              select c;

                _totalCount = cardQry.Count();

                int pageCount = _pageNumber - 1;

                cardData = cardQry.OrderBy(_x => _x.CARD_IDE).Skip(pageCount * 20).Take(20).ToList();

                for (int i = 0; i < cardData.Count; i++)
                {
                    CARD card = cardData[i];

                    if (cardData.Any(_item => _item.CARD_MASTER_IDE == card.CARD_IDE))
                    {
                        cardData.Remove(card);
                    }
                }

                listCards = DataConverter.ListCardDATAToListCardInfo(cardData);
            }
            else
            {
                // If we are here then the user browsed to get the 300 latest entries available.

                Expression<Func<CARD, bool>> cardPredicate = PredicateBuilder.True<CARD>();

                if (_rarity != "All")
                {
                    cardPredicate = cardPredicate.And(_item => _item.CARD_RARTY == _rarity);
                }

                if (_type != "All")
                {
                    cardPredicate = cardPredicate.And(_item => _item.CARD_TYPE.Contains(_type));
                }

                if (_color != "All")
                {
                    cardPredicate =
                        cardPredicate.And(
                            _item => _item.CARD_MANA_COST.Contains(_color) || _item.CARD_COLOR.Contains(_color));
                }

                var cardQry = (from c in db.CARD.AsExpandable().Where(_item => !_item.CARD_NAME.Contains("(Foil)"))
                                select c).OrderByDescending(_x => _x.CARD_SET.CARD_SET_RELES_DATE).Take(300);

                cardQry = cardQry.Where(cardPredicate);

                _totalCount = cardQry.Count();

                int pageCount = _pageNumber - 1;

                cardData = cardQry.Skip(pageCount * 20).Take(20).ToList();

                for (int i = 0; i < cardData.Count; i++)
                {
                    CARD card = cardData[i];

                    if (cardData.Any(_item => _item.CARD_MASTER_IDE == card.CARD_IDE))
                    {
                        cardData.Remove(card);
                    }
                }

                listCards = DataConverter.ListCardDATAToListCardInfo(cardData);
            }

            List<CardDisplay> listToReturn = MakeListCardDisplay(listCards);

            return listToReturn;
        }
    }
}

我的问题不是关于“我如何”执行我的代码(但我可以自由地做出建设性的评论,因为我喜欢学习),而是关于它是如何构建的。我想,例如,一个CardData完全由类实例化,这意味着我不能,例如,创建一个public static readonly CardData mCardDAL = new CardData();对象在控制器中。

有没有办法隔离我的课程,以至于任何人都被“强迫”通过经理来获取对象?我工作得很好,我的代码好吗?

4 个答案:

答案 0 :(得分:4)

可以通过在CardData中设置Manager嵌套类来拒绝来自外部的访问,通过使其成为protected来阻止它的构造函数,并创建一个private实例类:

public class Manager
{
    public class Manager
    {
        CardData c = new CardDataInternal();
    }

    private class CardDataInternal : CardData
    {
        public CardDataInternal()
        { }
    }

    public class CardData
    {
        protected CardData()
        { }
    }
}

答案 1 :(得分:3)

您可以通过将 manager 类设置为嵌套类来保持两个对象公开,然后为Card类提供私有构造函数(允许嵌套类调用),类似于:

public class Card
{
    private Card()
    {

    }
    public class Manager
    {
        public Card Create()
        {
            return new Card();
        }
    }
}

因此,您可以自由创建new Card.Manager(),但创建新Card的唯一方法是使用Create()方法。

答案 2 :(得分:2)

使用接口的@ Patrick方法的替代方法:

public interface ICardData { ... }
public class Manager
{
    public class Manager()
    {
        CardData c = new CardData();
    }

    private class CardData : ICardData
    {
        public CardData() { }
    }
}

通过在嵌套的私有类上使用接口而不是构造函数,您还可以设置使用模拟实现进行单元测试...对于CardData可能不重要但是如果您在具有此类的类上执行此操作有趣的行为,非常重要。

答案 3 :(得分:1)

从提供的代码中,您可能希望将CardData类放在CardManager类中并将其设置为私有,以便只有CardManager才能访问它。

public class CardManager
{
    private class CardData { ... }
}