九、结构型模式之装饰、组合、外观、享元-----《大话设计模式》

一、装饰模式

    动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

    装饰模式是利用SetComponent来对对象进行包装的,这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链中。

    如果只有一个ConcreteComponent类没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类;如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator责任合并成一个类。

    适用:装饰模式是为已有功能动态地添加更多功能的一种方式,当系统需要新功能的时候,是向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为。

    优点:把类中的装饰功能从类中搬移去除,这样可以简化原有的类;有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中的装饰逻辑。只是装饰时要注意顺序。

   

image

abstract class Component
    {
        public abstract void Operation();
    }
class ConcreteComponent : Component
    {
        public override void Operation()
        {
            Console.WriteLine("具体对象的操作");
        }
    }
//装饰抽象类
abstract class Decorator : Component
    {
        protected Component component;

        public void SetComponent(Component component)
        {
            this.component = component;
        }
          
        //重写Operation(),实际执行的是component的Operation()
public override void Operation()
        {
            if (component != null)
            {
                component.Operation();
            }
        }
    }

//具体的装饰对象
    class ConcreteDecoratorA : Decorator
    {
        private string addedState;

        public override void Operation()
        {
            //首先运行component的Operation(),再执行本类的功能
              base.Operation();
            addedState = "New State";
            Console.WriteLine("具体装饰对象A的操作");
        }
    }

    class ConcreteDecoratorB : Decorator
    {

        public override void Operation()
        {
            base.Operation();
            Console.WriteLine("具体装饰对象B的操作");
        }
static void Main(string[] args)
        {
            ConcreteComponent c = new ConcreteComponent();
            ConcreteDecoratorA d1 = new ConcreteDecoratorA();
            ConcreteDecoratorB d2 = new ConcreteDecoratorB();
            
            //先实例化对象c,用d1来包装c
              d1.SetComponent(c);
            //再用d2来包装d1
              d2.SetComponent(d1);
            //最终执行d2的Operation()
            d2.Operation();

            Console.Read();
        }

二、组合模式

    将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

    适用:需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地适用组合结构中的所有对象时,就应该考虑用组合模式了。

image

abstract class Component
    {
        protected string name;

        public Component(string name)
        {
            this.name = name;
        }

        //通常都用Add和Remove方法来提供增加或移除树叶或树枝的功能
         public abstract void Add(Component c);
        public abstract void Remove(Component c);
        public abstract void Display(int depth);
    }

    class Composite : Component
    {
        //一个子对象集合用来存储其下属的枝节点和页节点
         private List<Component> children = new List<Component>();

        public Composite(string name)
            : base(name)
        { }

        public override void Add(Component c)
        {
            children.Add(c);
        }

        public override void Remove(Component c)
        {
            children.Remove(c);
        }

        public override void Display(int depth)
        {
            //显示其枝节点名称,并对其下级进行遍历
              Console.WriteLine(new String('-', depth) + name);

            foreach (Component component in children)
            {
                component.Display(depth + 2);
            }
        }
    }

    //由于叶子没有再增加分支和树叶,所以Add和Remove方法实现它没有意义,但这样做可以消除页节点和枝节点对象再抽象层次的区别,它们具备完全一致的接口
    class Leaf : Component
    {
        public Leaf(string name)
            : base(name)
        { }

        public override void Add(Component c)
        {
            Console.WriteLine("Cannot add to a leaf");
        }

        public override void Remove(Component c)
        {
            Console.WriteLine("Cannot remove from a leaf");
        }

        public override void Display(int depth)
        {
            //显示名称和级别
              Console.WriteLine(new String('-', depth) + name);
        }
    }
static void Main(string[] args)
        {
            //生成树根root,根上长出两叶LeafA和LeafB
            Composite root = new Composite("root");
            root.Add(new Leaf("Leaf A"));
            root.Add(new Leaf("Leaf B"));

            //根上长出分支Composite X,分支上长出两叶LeafXA和LeafXB
            Composite comp = new Composite("Composite X");
            comp.Add(new Leaf("Leaf XA"));
            comp.Add(new Leaf("Leaf XB"));

            root.Add(comp);
          
            //Composite X上长出分支Composite XY,分支上长出两叶LeafXYA和LeafXYB
            Composite comp2 = new Composite("Composite XY");
            comp2.Add(new Leaf("Leaf XYA"));
            comp2.Add(new Leaf("Leaf XYB"));

            comp.Add(comp2);

           //根上长出两叶LeafC和LeafD,又移除了LeafD,
            root.Add(new Leaf("Leaf C"));
            Leaf leaf = new Leaf("Leaf D");
            root.Add(leaf);
            root.Remove(leaf);

            root.Display(1);

            Console.Read();
        }

三、外观模式

    为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

    适用:首先,在设计初期阶段,应该要有意识的将不同的两个层分离(MVC);其次,在开发阶段子系统往往因为不断的重构演化而变得越来越复杂,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖;第三,在维护一个遗留的大型系统时,非常难以维护和扩展,可以提供设计粗糙或高度复杂的遗留代码的比较清晰的简单接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。

image

//外观类,它需要了解所有的子系统的方法或属性,进行组合,以备外界调用
class Facade
    {
        SubSystemOne one;
        SubSystemTwo two;
        SubSystemThree three;
        SubSystemFour four;

        public Facade()
        {
            one = new SubSystemOne();
            two = new SubSystemTwo();
            three = new SubSystemThree();
            four = new SubSystemFour();
        }

        public void MethodA()
        {
            Console.WriteLine("
方法组A() ---- ");
            one.MethodOne();
            two.MethodTwo();
            four.MethodFour();
        }

        public void MethodB()
        {
            Console.WriteLine("
方法组B() ---- ");
            two.MethodTwo();
            three.MethodThree();
        }
    }
class SubSystemOne
    {
        public void MethodOne()
        {
            Console.WriteLine(" 子系统方法一");
        }
    }

    class SubSystemTwo
    {
        public void MethodTwo()
        {
            Console.WriteLine(" 子系统方法二");
        }
    }

    class SubSystemThree
    {
        public void MethodThree()
        {
            Console.WriteLine(" 子系统方法三");
        }
    }

    class SubSystemFour
    {
        public void MethodFour()
        {
            Console.WriteLine(" 子系统方法四");
        }
    }
//由于Facade的作用,客户端可以根本不知道子系统类的存在
static void Main(string[] args)
        {
            Facade facade = new Facade();

            facade.MethodA();
            facade.MethodB();

            Console.Read();

        }

四、享元模式

    运用共享技术有效地支持大量细粒度的对象。

    享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目,例如围棋游戏等。

适用:1.如果一个应用程序适用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;2.对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。string就是运用了享元模式(值引用)。

    image

    class FlyweightFactory
    {
        private Hashtable flyweights = new Hashtable();

        public FlyweightFactory()
        {
            //先生成三个实例
              flyweights.Add("X", new ConcreteFlyweight());
            flyweights.Add("Y", new ConcreteFlyweight());
            flyweights.Add("Z", new ConcreteFlyweight());

        }

        public Flyweight GetFlyweight(string key)
        {
            //根据客户端请求,获得已生成的实例
              return ((Flyweight)flyweights[key]);
        }
    }
    abstract class Flyweight
    {
        public abstract void Operation(int extrinsicstate);
    }

    class ConcreteFlyweight : Flyweight
    {
        public override void Operation(int extrinsicstate)
        {
            Console.WriteLine("具体Flyweight:" + extrinsicstate);
        }
    }

    class UnsharedConcreteFlyweight : Flyweight
    {
        public override void Operation(int extrinsicstate)
        {
            Console.WriteLine("不共享的具体Flyweight:" + extrinsicstate);
        }
    }
        static void Main(string[] args)
        {
            int extrinsicstate = 22;

            FlyweightFactory f = new FlyweightFactory();

            Flyweight fx = f.GetFlyweight("X");
            fx.Operation(--extrinsicstate);

            Flyweight fy = f.GetFlyweight("Y");
            fy.Operation(--extrinsicstate);

            Flyweight fz = f.GetFlyweight("Z");
            fz.Operation(--extrinsicstate);

            UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight();

            uf.Operation(--extrinsicstate);

            Console.Read();
        }

五、对比

代理模式

外观模式

代表一个单一对象 代表一个子系统
客户对象无法直接访问目标对象(由代理提供的单独的目标对象的访问控制) 可以直接访问子系统中的各个对象,但通常由外观对象提供对子系统各元件功能的简化的共同层次的调用接口
原文地址:https://www.cnblogs.com/shanymen/p/4827469.html