Возвратите непрозрачный объект вызывающей стороне, не нарушая безопасность типов

У меня есть метод, который должен возвратить снимок текущего состояния и другой метод, который восстанавливает то состояние.

public class MachineModel
{
    public Snapshot CurrentSnapshot { get; }
    public void RestoreSnapshot (Snapshot saved) { /* etc */ };
}

Состояние Snapshot класс должен быть абсолютно непрозрачным вызывающей стороне - никакие видимые методы или свойства - но его свойства не должны быть видимы в MachineModel класс. Я мог, очевидно, сделать это downcasting, т.е. иметь CurrentSnapshot возвратитесь object, и имейте RestoreSnapshot примите object аргумент, который это бросает к a Snapshot.

Но вызванный кастинг как этот заставляет меня чувствовать себя грязным. Каков лучший альтернативный дизайн, который позволяет мне быть и безопасным с точки зрения типов и непрозрачным?

Обновление с решением:

Я волновал выполнение комбинации принятого ответа и предложения об интерфейсах. Snapshot класс был сделан общедоступным абстрактным классом с частной реализацией внутри MachineModel:

public class MachineModel
{
    public abstract class Snapshot
    {
        protected internal Snapshot() {}
        abstract internal void Restore(MachineModel model);
    }

    private class SnapshotImpl : Snapshot
    {
        /* etc */
    }

    public void Restore(Snapshot state)
    {
        state.Restore(this);
    }
}

Поскольку конструктор и методы Snapshot internal, вызывающие стороны снаружи блока рассматривают его как абсолютно непрозрачное и не могут наследоваться ему. Вызывающие стороны в рамках блока могли звонить Snapshot.Restore вместо MachineModel.Restore, но это не большая проблема. Кроме того, на практике Вы никогда не могли реализовывать Snapshot.Restore без доступа к MachineModelчлены парламента, не занимающие официального поста, которые должны отговорить людей от попытки сделать так.

6
задан JSBձոգչ 1 June 2010 в 14:27
поделиться

3 ответа

Вы можете отменить зависимость и сделать Snapshot дочерним (вложенным классом) MachineModel. Тогда Snapshot имеет только открытый (или внутренний) метод Restore () , который принимает в качестве параметра экземпляр MachineModel. Поскольку моментальный снимок определяется как дочерний элемент MachineModel, он может видеть закрытые поля MachineModel.

Чтобы восстановить состояние, у вас есть два варианта в примере ниже. Вы можете вызвать Snapshot.RestoreState (MachineModel) или MachineModel.Restore (Snapshot) *.

public class MachineModel
{
    public class Snapshot
    {
        int _mmPrivateField;

        public Snapshot(MachineModel mm) 
        { 
            // get mm's state
            _mmPrivateField = mm._privateField;
        }

        public void RestoreState(MachineModel mm) 
        { 
            // restore mm's state
            mm._privateField = _mmPrivateField;
        }
    }

    int _privateField;

    public Snapshot CurrentSnapshot
    {
        get { return new Snapshot(this); }
    }

    public void RestoreState(Snapshot ss)
    {
        ss.Restore(this);
    }
}

Пример:

    MachineModel mm1 = new MachineModel();
    MachineModel.Snapshot ss = mm1.CurrentSnapshot;
    MachineModel mm2 = new MachineModel();
    mm2.RestoreState(ss);

* Было бы лучше иметь Snapshot.RestoreState () как internal и выводить всех вызывающих объектов за пределы сборки, поэтому единственный способ выполнить восстановление - через MachineModel.RestoreState ( ). Но в ответе Джона вы упомянули, что в одной сборке будут вызывающие абоненты, поэтому в этом нет особого смысла.

2
ответ дан 16 December 2019 в 21:35
поделиться

Могут ли MachineModel и Snapshot находиться в одной сборке, а вызывающие объекты - в другой сборке? Если это так, то Snapshot может быть открытым классом, но с полностью внутренними членами.

3
ответ дан 16 December 2019 в 21:35
поделиться

Очевидно, я мог бы сделать это, понижающее преобразование, т.е. иметь CurrentSnapshot вернуть объект и иметь RestoreSnapshot принимает объект аргумент, который он возвращает Снимок.

Проблема в том, что кто-то может затем передать экземпляр объекта, который не является снимком .

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

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

3
ответ дан 16 December 2019 в 21:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: