Изменение внутреннего представления во время выполнения

ОБНОВЛЕНИЕ Основные вопросы остаются в примере, но я думаю, что это сводится к следующему:

** Если у вас есть тип, в котором 99% значений могут быть представлены в одном быстром, мощном типе и только 1% в очень тяжелом типе (скажем, int или BigInteger), как это представить?? **

В школе мы многое узнали о внутренних представлениях, но никогда не знали, как изменить их во время выполнения. Я имею в виду: предположим, у вас есть класс, представляющий десятичное число, но вы используете целое число для его внутреннего представления, пока вам действительно не понадобится большее значение, чем целое число, и только изменение представления...

Я никогда не думал об этом раньше, и когда я думал об этом, я думал, что это никогда не сработает, так как все проверки убьют его. Но я только что провел тест, так как мне слишком любопытно для моего же блага, и существуют ситуации, когда изменение представления более эффективно: с учетом этого интерфейса:

interface INumber
    {
        void add1000();
        void SetValue(decimal d);
        decimal GetValue();                     
    } 

Я обнаружил, что последняя из двух реализаций более мощная во многих ситуациях, включая эту который я сочинил, чтобы привлечь как можно больше идей по этому вопросу (не репутация, это сообщество)

    1. Representation by only a decimal

        public class Number1:INumber
        {

            private decimal d { get; set; }


            public void add1000()
            {
                d += 1000;
            }



            public decimal GetValue()
            {
                return d;
            }



            public void SetValue(decimal d)
            {
                this.d = d;
            }

        }


2. Representation by a decimal and an int

public class Number2:INumber
    {
        private bool usedecimal; 
        private int i;
        private decimal d;

        public void add1000()
        {
            if (usedecimal)
            {
                d += 1000;
                return; 
            }

            i += 1000;

            if (i > 2147480000)
            {
                d = i;              
                usedecimal = true;              
            }


        }

        public void SetValue(decimal d)
        {
            try
            {
                i = (int)d;

            }
            catch (OverflowException e)
            {

                this.d = d;
            }

        }

        public decimal GetValue()
        {
            return Math.Max(i,d);
        }
    }
}

Мой вопрос заключается в следующем:

Это кажется что-то. Я пропал без вести, но это должно быть очевидное кровотечение. Может ли кто-нибудь помочь мне с этим?

  • Существуют ли рекомендации для смешанных представлений, когда их использовать, а когда нет?
  • Как догадаться, что смешанная репрестенция может быть быстрее без бенчмаркинга?
  • Есть примеры?
  • Любые узоры?
  • Есть идеи по этому поводу?

person Peter    schedule 10.11.2009    source источник
comment
И ваш вопрос...?   -  person Kevin    schedule 10.11.2009
comment
@kevin, извините, не был полным   -  person Peter    schedule 10.11.2009


Ответы (2)


Если у вас есть тип, в котором 99% значений могут быть представлены в одном быстром, мощном типе и только 1% в очень тяжелом типе (скажем, int против BigInteger), как это представить??

Реализации BigInteger обычно делают именно это; они хранят все в int или long, пока что-то не переполнится, и только тогда они переходят к более тяжелой реализации.

Существует множество способов представить это. Шаблон, который мне нравится, это:

public abstract class Thing
{
    private class LightThing : Thing
    { ... }
    private class HeavyThing : Thing 
    { ... }
    public static Thing MakeThing(whatever) 
    { /* make a heavy or light thing, depending */ }
    ... etc ...
}

Существуют ли рекомендации для смешанных представлений, когда их использовать, а когда нет?

Конечно. Мы можем легко составить такой список. Эта техника имеет смысл, если:

(1) облегченная реализация намного легче тяжелой реализации

(2) типичное использование в большинстве случаев попадает в путь облегченного кода

(3) стоимость обнаружения перехода незначительна по сравнению со стоимостью тяжеловесного решения

(4) более сложное решение с двумя представлениями необходимо для достижения реалистичной цели производительности, ориентированной на клиента.

Как догадаться, что смешанная репрестенция может быть быстрее без бенчмаркинга?

Не. Принятие решений о производительности на основе догадок — это рассуждения, опережающие факты. Принимайте решения об эффективности на основе реалистичного, ориентированного на клиента, на основе данных анализа, а не на догадках. Если я что-то и понял об анализе производительности за эти годы, так это то, что мои догадки обычно неверны.

Есть примеры?

Любое количество реализаций BigInteger.

Любые узоры?

Бьет черт из меня. Я не очень хорошо запоминаю таксономию шаблонов.

Есть идеи по этому поводу?

См. выше.

person Eric Lippert    schedule 10.11.2009
comment
Это отличный пример того, как реализовать такую ​​систему; фабричный шаблон (используемый, как я полагаю, с неизменяемым классом) является лучшим шаблоном для подражания, чем изменение внутреннего представления во время выполнения. Это может показаться семантической разницей, так как по сути делается одно и то же, но это кажется гораздо более чистым способом работы. - person Adam Robinson; 11.11.2009

Возможно, вы ищете шаблон моста.

person Joel Lucsy    schedule 10.11.2009