动态CMS组件的模式(事件驱动?)

时间:2010-04-24 20:01:08

标签: php design-patterns oop content-management-system

对不起,我的头衔并不是很好,这是我第一次将100%转移到OO,因为我的程序已经超过了我的记忆。我发现很难理解我正在尝试做的事情是否可行。根据人们对以下两点的看法,我会走这条路。

我正在整理的CMS很小,但非常关注不同类型的内容。我可以轻松使用Drupal,我很满意,但我想给自己一个很好的理由让我自己进入设计模式/ OO-PHP

1) 我创建了一个基本的“内容”类,我希望能够扩展它来处理不同类型的内容。例如,基类处理HTML内容,而扩展可能会处理XML或PDF输出。另一方面,在某些时候,我可能希望完全扩展给定项目的基类。即如果该类网站的'content-v2'扩展类'内容',则对该类的任何调用实际上都应该调用'content-v2'。这可能吗?

如果代码实例化了一个'content'类型的对象 - 我实际上希望它实例化一个'content-v2'类型......我可以看到如何使用继承来实现它,但这似乎涉及到引用明确地说,我无法看到如何链接我希望它动态使用的类。

2) 其次,我现在建立这种方式的方式太可怕了,我对此并不满意。确实感觉非常线性 - 即获取会话详细信息>获取内容>构建导航>主题页>发布。为此,所有对象都被称为1-by-1,这些都是非常静态的。我希望它更具动态性,以便我可以在以后添加它(与第一个问题非常相关)。

有没有办法代替我的orchestrator类1-by-1调用所有其他类,然后在最后构建整个事件,而不是其他每个类都可以“监听”特定事件,然后在适用的点上跳进去做但他们呢?这样,orchestrator类就不需要知道需要什么其他类,并且逐个调用它们。

很抱歉,如果我把这一切都扭曲了。我正在尝试构建它,因此它非常灵活。

1 个答案:

答案 0 :(得分:1)

关于使用ContentContent-v2(这些名字很糟糕,顺便说一句)的问题......

  1. 详细了解encapsulationpolymorphism
  2. 我认为你需要一个BaseContent类,它是一个抽象类,除了通过继承之外,它永远不会以任何方式被消费。
  3. BaseContent课程中,您应该有HtmlContentPdfContentMSWordContent等课程。如果你愿意,你甚至可以扩展这些,例如使用HtmlReportContent(扩展HtmlContent),MSWord2010内容等。
  4. 这样做,您可以声明和存储所有类型BaseContent的变量,但是当您实例化它们时,您将它们实例化为您的特定类型。执行此操作时,即使您在BaseContent类中实现了Render()方法,您的子类也可以选择使用基本Render()方法或覆盖它并提供自己的实现,甚至覆盖它,提供一点自定义实现,然后调用基础实现以从该实现中受益。
  5. 如果您有共享实现或行为(例如,ChihuahuaGermanShepard类都将具有Bark()函数,但它们将以不同方式实现),则抽象共享基类的实现或行为。你不一定要在你的基类中提供一个实现 - 这就是为什么它是一个抽象类 - 然后强制你的子类实现它(Bark()将在你的BaseDog类中定义但不是实现)。

    至于你系统的流程...... 对于面向对象的设计,考虑设计state machine并且您的对象基本上填写了状态机的目的以及从一个状态到另一个状态的每个变化。是的,可能有一种方法可以通过您的状态流程图来覆盖50%的情景,但我们都知道用户会偏离这种情况。因此,您需要定义用户可以偏离它的方式,并允许那些但限制为那些。您可能会或可能不会实际绘制流程图,具体取决于系统的复杂程度。但有时候,通过抽出部分可能性,可以看出一些可能性。但是,通常情况下,这个图表对于大多数OO系统实际创建来说太大了。如果你正在为NASA做一个系统,你可能会拥有它。 :-P

    以下是一些代码,可帮助说明其中的一些内容(并在评论中解决您的一些问题)。但是,我不是一个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;
        }
    }
    

    我希望这会有所帮助。