2013-05-04 2 views
1

Я провел последний день, пытаясь разработать, какой шаблон лучше всего подходит для моего конкретного сценария, и я подбрасывал между шаблоном состояния Pattern &. Когда я читаю примеры в Интернете, это имеет смысл ... но это еще один навык, который пытается применить его к вашей собственной проблеме. Я опишу свой сценарий и проблему, с которой я столкнулся, и, надеюсь, кто-то может указать мне в правильном направлении.Проблема программирования OO - шаблон государственного дизайна

Проблема: у меня есть базовый объект, который имеет разные состояния синхронизации: т.е. последний, старый, никогда не опубликованный, не опубликованный и т. Д. Теперь, в зависимости от того, какое состояние объект в поведении отличается, например, вы не можете получить последнюю версию для базового объекта, который никогда не публиковался. На данный момент кажется, что модель дизайна штата лучше всего подходит ... поэтому я ее реализовал, и теперь у каждого штата есть такие методы, как CanGetLatestVersion, GetLatestVersion, CanPublish, Publish и т. Д.

В этом все хорошо. Но давайте предположим, что у вас есть 10 разных дочерних объектов, которые происходят из базового класса ... мое решение нарушено, потому что, когда для каждого состояния выполняется «публиковать» метод, ему нужны свойства в дочернем объекте для фактического выполнения операции, но каждое состояние имеет только ссылку на базовый объект. Я только что потратил некоторое время на создание типового проекта, иллюстрирующего мою проблему на C#.

public class BaseDocument 
{ 
    private IDocumentState _documentState; 

    public BaseDocument(IDocumentState documentState) 
    { 
     _documentState = documentState; 
    } 

    public bool CanGetLatestVersion() 
    { 
     return _documentState.CanGetLatestVersion(this); 
    } 

    public void GetLatestVersion() 
    { 
     if(CanGetLatestVersion()) 
      _documentState.CanGetLatestVersion(this); 
    } 

    public bool CanPublish() 
    { 
     return _documentState.CanPublish(this); 
    } 

    public void Publish() 
    { 
     if (CanPublish()) 
      _documentState.Publish(this); 
    } 

    internal void Change(IDocumentState documentState) 
    { 
     _documentState = documentState; 
    } 
} 

public class DocumentSubtype1 : BaseDocument 
{ 
    public string NeedThisData { get; set; } 
} 

public class DocumentSubtype2 : BaseDocument 
{ 
    public string NeedThisData1 { get; set; } 
    public string NeedThisData2 { get; set; } 
} 

public interface IDocumentState 
{ 
    bool CanGetLatestVersion(BaseDocument baseDocument); 
    void GetLatestVersion(BaseDocument baseDocument); 
    bool CanPublish(BaseDocument baseDocument); 
    bool Publish(BaseDocument baseDocument); 
    SynchronizationStatus Status { get; set; }  
} 

public class LatestState : IDocumentState 
{ 
    public bool CanGetLatestVersion(BaseDocument baseDocument) 
    { 
     return false; 
    } 

    public void GetLatestVersion(BaseDocument baseDocument) 
    { 
     throw new Exception(); 
    } 

    public bool CanPublish(BaseDocument baseDocument) 
    { 
     return true; 
    } 

    public bool Publish(BaseDocument baseDocument) 
    { 
     //ISSUE HERE... I need to access the properties in the the DocumentSubtype1 or DocumentSubType2 class. 
    } 

    public SynchronizationStatus Status 
    { 
     get 
     { 
      return SynchronizationStatus.LatestState; 
     } 
    } 
} 

public enum SynchronizationStatus 
{ 
    NeverPublishedState, 
    LatestState, 
    OldState, 
    UnpublishedChangesState, 
    NoSynchronizationState 
} 

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

Любая помощь была бы принята с благодарностью. Если это смущает, пожалуйста, дайте мне знать, чтобы я мог уточнить!

Приветствия

+0

Что именно вы подразумеваете под * «10 различных дочерних объектов, которые происходят из базового класса» *? Эта часть немного запутанна. – acdcjunior

+0

Я добавил несколько примеров кода, чтобы помочь проиллюстрировать проблему.В этом случае есть только 2 дочерних объекта, то есть DocumentSubtype1 & DocumentSubtype2 – Fred

ответ

0

Давайте переосмыслить это, полностью.

1) У вас есть локальная «ручка», для некоторых данных, которыми вы действительно не владеете. (Некоторые из них хранятся или публикуются в другом месте).

2) Возможно, ручка, это то, что мы называли ранее «State» - простой общий API, без деталей реализации.

3) Вместо делегирования «CanPublish», «GetLatestVersion» из BaseDocument в State - это похоже на то, что Handle должен делегировать конкретную реализацию DocumentStorage.

4) При представлении внешних государств или мест хранения, использование отдельного объекта идеально подходит для инкапсулирования New/несуществующей/делеция состояния & идентификатора, в этом месте хранения.

5) Я не уверен, что «Версии» являются частью «Опубликованного местоположения»; или если это два независимых места хранения. Наша ручка нуждается в представлении «Состояние хранилища» для каждого независимого местоположения, которое оно будет хранить в/из.

Например:

Handle 
    - has 1 LocalCopy with states (LOADED, NOT_LOADED) 
    - has 1 PublicationLocation with Remote URL and states (NEW, EXIST, UPDATE, DELETE) 

Handle.getVersions() then delegates to PublicationLocation. 
Handle.getCurrent() loads a LocalCopy (cached), from PublicationLocation. 
Handle.setCurrent() sets a LocalCopy and sets Publication state to UPDATE. 
    (or executes the update immediately, whichever.) 

удаленного хранение/Транспорты могут быть субтипированы для различных методов доступа, или LocalCopy/Документа может быть субтипирован для различных типов контента.

ЭТО, Я ПРЕДВАРИТЕЛЬНО УВЕРЕН, БОЛЬШЕ ПРАВИЛЬНОЕ РЕШЕНИЕ.


[Ранее] Keep «State» несколько отдельно от объекта «документ» (давайте назовем это документ, так как мы должны называть его что-то. - и вы не указали)

Создайте свою иерархию из BaseDocument down, используйте элемент BaseDocument.State и создайте объекты State со ссылкой на их экземпляр Document - чтобы они имели доступ к &, можно работать с деталями.

По существу:

  • BaseDocument < --friend -> Государственный
  • Документ подтипа наследуют от BaseDocument.
  • защищенных методов & членов в иерархии документов, позволяют государству делать все, что ему нужно.

Надеюсь, это поможет.

+0

Спасибо за ответ ... Я не уверен, что я точно понимаю, что вы имеете в виду. Я добавил несколько примеров кода в исходное сообщение ... можете ли вы дать дополнительное объяснение? ура – Fred

0

Многие шаблоны проектирования могут использоваться для решения этой проблемы архитектуры. К сожалению, вы не приводите пример того, как вы публикуете. Тем не менее, я выскажу некоторые из хороших конструкций:

  1. Поместите дополнительные параметры базового документа и сделать его обнуляемым. Если он не используется в документе, он равен нулю. В противном случае это значение . Здесь вам не нужно наследование.

  2. Не ставьте метод публикации на DocumentState, вместо этого помещаем в BaseDocument. Логически, метод Publish должен быть частью из BaseDocument вместо DocumentState.

  3. Позвольте другому классу обслуживания обращаться к изданию (издатель ). Вы можете достичь этого, используя абстрактный заводской шаблон. Этот путь , вам нужно создать документ 1: 1: объект издателя. Это может быть , но у вас есть свобода изменять издателя каждого документа.

    public interface IPublisher<T> where T : BaseDocument 
    { 
        bool Publish(T document); 
    } 
    
    public interface IPublisherFactory 
    { 
        bool Publish(BaseDocument document); 
    } 
    
    public class PublisherFactory : IPublisherFactory 
    { 
        public PublisherFactory(
         IPublisher<BaseDocument> basePublisher 
         , IPublisher<SubDocument1> sub1Publisher) 
        { 
         this.sub1Publisher = sub1Publisher; 
         this.basePublisher = basePublisher; 
        } 
        IPublisher<BaseDocument> basePublisher; 
        IPublisher<SubDocument1> sub1Publisher; 
    
        public bool Publish(BaseDocument document) 
        { 
         if(document is SubDocument1) 
         { 
          return sub1Publisher.Publish((SubDocument1)document); 
         } 
         else if (document is BaseDocument) 
         { 
          return basePublisher.Publish(document); 
         } 
         return false; 
        } 
    } 
    
    public class LatestState : IDocumentState 
    { 
        public LatestState(IPublisherFactory factory) 
        { 
         this.factory = factory; 
        } 
        IPublisherFactory factory; 
    
        public bool Publish(BaseDocument baseDocument) 
        { 
         factory.Publish(baseDocument); 
        } 
    } 
    
  4. Использование Composition over inheritance. Вы проектируете каждый интерфейс для каждого состояния, а затем составляете его в документе. Таким образом, вы можете иметь 5 CanGetLatestVersion и другой класс композиции, но 10 класс композиции издателя.

  5. Более продвинутый и основанный на используемом вами репозитории, возможно, вы можете использовать Visitor pattern. Таким образом, вы можете свободно изменять каждый метод публикации. Это похоже на мою точку 3, за исключением того, что она объявляется в одном классе. Например:

    public class BaseDocument 
    { 
    
    } 
    public class SubDocument1 : BaseDocument 
    { 
    
    } 
    
    public class DocumentPublisher 
    { 
        public void Publish(BaseDocument document) 
        { 
    
        } 
        public void Publish(SubDocument1 document) 
        { 
         // do the prerequisite 
         Publish((BaseDocument)document); 
         // do the postrequisite 
        } 
    } 
    

Там могут быть и другие конструкции доступны, но это зависит от того, как получить доступ к хранилищу.

Смежные вопросы