Шаблоны для динамических компонентов CMS (управляемые событиями?) - PullRequest
2 голосов
/ 25 апреля 2010

Извините, мой титул не велик, это мой первый настоящий толчок при переходе на 100% к ОО, поскольку я был процедурным в течение многих лет, чем я помню. Мне трудно понять, возможно ли то, что я пытаюсь сделать. В зависимости от мыслей людей о 2 следующих пунктах, я пойду по этому пути.

CMS, которую я собираю, - это небольшая цитата, однако она очень сильно фокусируется на различных типах контента. Я мог бы легко использовать Drupal, с которым мне очень комфортно, но я хочу дать себе действительно веские причины для перехода к шаблонам проектирования / OO-PHP

1) Я создал базовый класс контента, который я хотел бы расширить для работы с разными типами контента. Например, базовый класс обрабатывает содержимое HTML, а расширения могут обрабатывать вывод XML или PDF. С другой стороны, в какой-то момент я могу пожелать полностью расширить базовый класс для данного проекта. То есть если класс «content-v2» расширенный класс «content» для этого сайта, любые вызовы этого класса должны фактически вызывать «content-v2». Это возможно?

Если код создает экземпляр объекта типа «контент» - я на самом деле хочу, чтобы он создал экземпляр объекта типа «контент-v2» ... Я могу видеть, как это сделать, используя наследование, но, похоже, это связано со ссылкой на класс явно, я не вижу, как связать класс, который я хочу использовать вместо него динамически.

2) Во-вторых, то, как я сейчас это строю, ужасно, я не доволен этим. Это действительно очень линейно - то есть получить информацию о сеансе> получить контент> построить навигацию> страницу темы> опубликовать. Для этого все объекты называются 1 на 1, что очень статично. Мне бы хотелось, чтобы он был более динамичным, чтобы я мог добавить его позже (очень тесно связанный с первым вопросом).

Есть ли способ, что вместо того, чтобы мой класс оркестратора вызывал все остальные классы 1 на 1, а затем собирал все целиком в конце, вместо этого каждый из других классов мог бы «прослушивать» определенные события, а затем в подходящей точке прыгать и делать их, но? Таким образом, классу оркестровщика не нужно будет знать, какие другие классы требуются, и называть их 1 на 1.

Извините, если я все это запутал в своей голове. Я пытаюсь построить это так, чтобы это было действительно гибко.

1 Ответ

1 голос
/ 25 апреля 2010

На ваш вопрос о работе с Content и Content-v2 (это ужасные имена, кстати) ...

  1. Перейти подробнее о инкапсуляция и полиморфизм
  2. Я думаю, вам нужен BaseContent класс, который является абстрактным классом, который никогда не потребляется никоим образом, кроме как наследованием.
  3. Из вашего BaseContent класса вы должны иметь классы HtmlContent, PdfContent, MSWordContent и т. Д. И если вы хотите, вы можете даже расширить их, например, с помощью HtmlReportContent (extends HtmlContent), MSWord2010Content и т. Д.
  4. Делая это таким образом, вы можете объявлять и хранить переменные всех типов BaseContent, но когда вы создаете их экземпляры, вы создаете их как свой определенный тип. Когда вы делаете это, даже если у вас есть метод Render (), реализованный в вашем классе BaseContent, ваши дочерние классы могут выбрать использование базового метода Render () или переопределить его и предоставить свою собственную реализацию, или даже переопределить его, предоставить немного пользовательская реализация, а затем вызвать базовую реализацию, чтобы извлечь выгоду и из этой реализации.

Если у вас есть общая реализация или поведение (например, класс Chihuahua и GermanShepard оба будут иметь функцию Bark(), но они будут реализованы по-разному), то абстрагируйте эту общую реализацию или поведение в базу учебный класс. Вам не обязательно предоставлять реализацию в вашем базовом классе - вот почему это абстрактный класс - тогда он заставляет ваши дочерние классы реализовать его (Bark() будет определен в вашем BaseDog классе, но не реализован).

Что касается потока вашей системы ... Для вашего объектно-ориентированного проектирования, подумайте о разработке конечного автомата 1034 *, и ваши объекты по существу заполняют назначение этого конечного автомата и каждое изменение из одного состояния в другое состояние. Да, возможно, есть один способ пройтись по вашей диаграмме потоков состояний, которая охватывает около 50% сценариев, но мы все знаем, что пользователи будут отклоняться от этого. Таким образом, вам нужно определить способы, которыми пользователь может отклониться от него и разрешить те, но ограничить их. Вы можете или не можете фактически нарисовать блок-схему, в зависимости от того, насколько сложна ваша система. Но иногда это помогает визуализировать некоторые возможности, вытягивая их часть. Однако, как правило, эта диаграмма будет слишком большой для большинства ОО-систем. Если бы вы делали систему для НАСА, то, вероятно, она у вас была бы. : -Р

Вот код, который поможет проиллюстрировать некоторые из этих вещей (и ответить на некоторые ваши вопросы в комментариях). Тем не менее, я НЕ парень по PHP, поэтому я собираюсь дать вам примеры на C #, но я сделаю их достаточно простыми, чтобы вы могли легко перевести на PHP.

public interface IAnimal
{
    string GetName();
    string Talk();
}

public abstract class AnimalBase : IAnimal
{
    private string _name;

    // Constructor #1
    protected AnimalBase(string name)
    {
        _name = name;
    }

    // Constructor #2
    protected AnimalBase(string name, bool isCutsey)
    {
        if (isCutsey)
        {
            // Change "Fluffy" into "Fluffy-poo"
            _name = name + "-poo";
        }
    }

    // GetName implemention from IAnimal.
    // In C#, "virtual" means "Let the child class override this if it wants to but is not required to"
    public virtual string GetName()
    {
        return _name;
    }

    // Talk "implementation" from IAnimal.
    // In C#, "abstract" means "require our child classes to override this and provide the implementation".
    // Since our base class forces child classes to provide the implementation, this takes care of the IAnimal implementation requirement.
    abstract public string Talk();
}

public class Dog : AnimalBase
{
    // This constructor simply passes on the name parameter to the base class's constructor.
    public Dog(string name)
        : base(name)
    {
    }

    // This constructor passes on both parameters to the base class's constructor.
    public Dog(string name, bool isCutsey)
        : base(name, isCutsey)
    {
    }

    // Override the base class's Talk() function here, and this satisfy's AnimalBase's requirement to provide this implementation for IAnimal.
    public override string Talk()
    {
        return "Woof! Woof!";
    }
}

public class SmallDog : Dog
{
    private bool _isPurseDog;

    // This constructor is unique from all of the other constructors.
    // Rather than the second boolean representing the "isCutsey" property, it's entirely different.
    // It's entirely a coincidence that they're the same datatype - this is not important.
    // Notice that we're saying ALL SmallDogs are cutsey by passing a hardcoded true into the base class's (Dog) second parameter of the constructor.
    public SmallDog(string name, bool isPurseDog)
        : base(name, true)
    {
        _isPurseDog = isPurseDog;
    }

    // This tells us if the dog fits in a purse.
    public bool DoesThisDogFitInAPurse()
    {
        return _isPurseDog;
    }

    // Rather than using Dog's Talk() implementation, we're changing this because this special type of dog is different.
    public override string Talk()
    {
        return "Yip! Yip!";
    }
}

public class Chihuahua : SmallDog
{
    private int _hatSize;

    // We say that Chihuahua's always fit in a purse. Nothing else different about them, though.
    public Chihuahua(string name, int hatSize)
        : base(name, true)
    {
        _hatSize = hatSize;
    }

    // Of course all chihuahuas wear Mexican hats, so let's make sure we know its hat size!
    public int GetHatSize()
    {
        return _hatSize;
    }
}

public class Cat : AnimalBase
{
    // This constructor simply passes on the name parameter to the base class's constructor.
    public Cat(string name)
        : base(name)
    {
    }

    // This constructor passes on both parameters to the base class's constructor.
    public Cat(string name, bool isCutsey)
        : base(name, isCutsey)
    {
    }

    // Override the base class's Talk() function here, and this satisfy's AnimalBase's requirement to provide this implementation for IAnimal.
    public override string Talk()
    {
        return "Meoooowwww...";
    }
}

public class Lion : Cat
{
    public Lion(string name)
        : base(name)
    {
    }

    // Rather than using Cat's Talk() implementation, we're changing this because this special type of cat is different.
    public override string Talk()
    {
        return "ROAR!!!!!!!!";
    }
}

public class ThisIsNotAGoodExampleOfObjectOrientedCoding
{
    public string DoStuff()
    {
        // To keep the C#-to-PHP translation easy, think of this as an array of IAnimal objects.
        List<IAnimal> myAnimals = new List<IAnimal>();

        IAnimal strayCat = new Cat("Garfield", false);
        Cat myPet = new Cat("Katrina");
        IAnimal myMothersDog = new Dog("Harley");
        Dog myMothersOtherDog = new Dog("Cotton");
        IAnimal myNeighborsDog = new SmallDog("Roxy", false);
        Dog movieStarsDog = new SmallDog("Princess", true);
        Dog tacoBellDog = new Chihuahua("Larry", 7);
        Lion lionKing = new Lion("Simba");

        myAnimals.Add(strayCat);
        myAnimals.Add(myPet);
        myAnimals.Add(myMothersDog);
        myAnimals.Add(myMothersOtherDog);
        myAnimals.Add(myNeighborsDog);
        myAnimals.Add(movieStarsDog);
        myAnimals.Add(tacoBellDog);
        myAnimals.Add(lionKing);

        string allAnimalsTalking = "";

        // Create a string to return.
        // Garfield says "Meow". Fido says "Woof! Woof!" etc...
        for (int i = 0; i < myAnimals.Count; i++)
        {
            allAnimalsTalking = allAnimalsTalking + myAnimals[i].GetName() + " says \"" + myAnimals[i].Talk() + "\" ";

            if (myAnimals[i] is SmallDog)
            {
                // Cast the IAnimal into a SmallDog object.
                SmallDog yippyDog = myAnimals[i] as SmallDog;

                if (yippyDog.DoesThisDogFitInAPurse())
                {
                    allAnimalsTalking = allAnimalsTalking + " from a purse.";
                }
            }
        }

        return allAnimalsTalking;
    }
}

Надеюсь, это поможет некоторым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...