设计模式之结构型模式

结构型模式涉及到如何组合类和对象以获得更大的结构。

结构型模式包括:适配器模式,桥接模式,装饰者模式,组合模式,外观模式,享元模式,代理模式

1.适配器模式

适配器:将一个类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类能一起工作。比如一般购物网站都能将自己喜欢的商品加入favorite,而亚马逊则是加入wishlist。我们想要一个统一的接口对所有网站都提供favorite接口,这时就需要用到适配器了。

abstract class OnlineShop
{
    public abstract void favorite();
}
class amazon
{
    public void wishlist()
    {
        Console.Write("my wishlist");
    }
}
class adaptedAmazon : OnlineShop
{
    amazon ama = new amazon();
    public override void favorite()
    {
        ama.wishlist();
    }
}

namespace model
{
    class Program
    {

        static void Main(string[] args)
        {
            OnlineShop shop = new adaptedAmazon();
            shop.favorite();
            Console.Read();
        }
    }
}
View Code

 

2.桥接模式

Bridge模式用来将抽象部分与它的实现部分分离,使它们都可以独立地变化。

这个有点类似于外包公司,这个外包公司给我们提供了一个服务列表,比如服务A是给我们提供B公司的C产品,这时外包公司的服务列表就是抽象部分,B公司则负责具体的生产,外包公司不关心B公司的具体生产,但是他可以通过对B公司的产品进行定制,生成不同的服务,B公司也不关心外包公司提供什么服务,而只是关心有哪些基本的产品需要生产。

class Abstraction
{
    protected Implementor implementor;

    public void SetImplementor(Implementor implementor)
    {
        this.implementor = implementor;
    }

    public virtual void Operation()
    {
        implementor.Operation();
    }

}

class RefinedAbstraction : Abstraction
{
    public override void Operation()
    {
        implementor.Operation();
    }
}

abstract class Implementor
{
    public abstract void Operation();
}

class ConcreteImplementorA : Implementor
{
    public override void Operation()
    {
        Console.WriteLine("具体实现A的方法执行");
    }
}

class ConcreteImplementorB : Implementor
{
    public override void Operation()
    {
        Console.WriteLine("具体实现B的方法执行");
    }
}
namespace model
{
    class Program
    {
        
        static void Main(string[] args)
        {
            Abstraction ab = new RefinedAbstraction();

            ab.SetImplementor(new ConcreteImplementorA());
            ab.Operation();

            ab.SetImplementor(new ConcreteImplementorB());
            ab.Operation();

            Console.Read();
        }
    }
}
View Code

优点:

1)分离接口及其实现部分,桥接模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。

2)实现细节对客户透明

3.组合模式

组合模式使得用户对单个对象和组合对象的使用具有一致性。

比如一副图像,它可能由很多图元和子图像组合而成,其中子图像可能又由图元和子图像组合而成,就像一棵多叉树。

 

class Graphic
{
    private List<Graphic> _graphics = new List<Graphic>();
    public void Add(Graphic graph)
    {
        _graphics.Add(graph);
    }
    public virtual void Draw()
    {
        Console.WriteLine("a graph:");
        foreach (Graphic graph in _graphics)
        {
            graph.Draw();
        }
    }
}
class Circle : Graphic
{
    public override void Draw()
    {
        Console.WriteLine("a circle");
    }
}
class Line : Graphic
{
    public override void Draw()
    {
        Console.WriteLine("a line");
    }
}

namespace model
{
    class Program
    {

        static void Main(string[] args)
        {

            Graphic graph = new Graphic();
            Graphic graph1 = new Graphic();
            graph1.Add(new Line());
            graph.Add(new Circle());
            graph.Add(graph1);
            graph.Draw();
            Console.Read();
        }
    }
}
View Code

 优点:

1)简化客户代码

2)使得更容易增加新类型的组件

3)使你的设计变得更加一般化

4.装饰者模式

装饰者模式:动态地给一个对象添加一些额外的职责。注意是给对象而不是类添加职责。

装饰者其实就是把对象包装了一下,把对对象额外进行的操作封装到了一个装饰类中。

abstract class Component
{
    public abstract void Operation();
}

class ConcreteComponent : Component
{
    public override void Operation()
    {
        Console.WriteLine("具体对象的操作");
    }
}

abstract class Decorator : Component
{
    protected Component component;

    public override void Operation()
    {
        component.Operation();
    }
}

class ConcreteDecoratorA : Decorator
{
    public ConcreteDecoratorA(Component component)
    {
        this.component = component;
    }
    public override void Operation()
    {
        base.Operation();
        Console.WriteLine("具体装饰对象A的操作");
    }
}

class ConcreteDecoratorB : Decorator
{
    public ConcreteDecoratorB(Component component)
    {
        this.component = component;
    }
    public override void Operation()
    {
        base.Operation();
        Console.WriteLine("具体装饰对象B的操作");
    }
}

namespace model
{
    class Program
    {

        static void Main(string[] args)
        {

            ConcreteComponent c = new ConcreteComponent();
            ConcreteDecoratorA d1 = new ConcreteDecoratorA(c);
            ConcreteDecoratorB d2 = new ConcreteDecoratorB(c);
            d1.Operation();
            d2.Operation();
            Console.Read();
        }
    }
}
View Code

 装饰者模式比静态继承灵活,可以动态的给一个对象加多个装饰。

 

5.外观模式

Facade模式为子系统中的一组接口提供一个一致的界面。

就好象我们画一个三角形,我们要依次画三角形的三条边,但是我们实际上并不关心这个三角形是怎样画出来的,我们只想要有一个画三角形的接口Draw,我们只要调用这个接口,就能画出这个三角形就行了。

   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(" 子系统方法四");
        }
    }

    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("\n方法组A() ---- ");
            one.MethodOne();
            two.MethodTwo();
            four.MethodFour();
        }

        public void MethodB()
        {
            Console.WriteLine("\n方法组B() ---- ");
            two.MethodTwo();
            three.MethodThree();
        }
    }

namespace model
{
    class Program
    {

        static void Main(string[] args)
        {

            Facade facade = new Facade();
            facade.MethodA();
            facade.MethodB();
            Console.Read();
        }
    }
}
View Code

 优点:

1)对客户屏蔽子系统组件

2)实现子系统与客户之间的松耦合关系

 

6.享元模式

当一个应用程序使用了大量的对象,造成很大的存储开销,且对象的大多数状态都可以变为外部状态,这时应该使用Flyweight模式,删除对象的外部状态,以便用相对较少的共享对象取代很多对象。

比如文档编辑器,若把编辑器中每个字符都作为一个对象显然会造成大量的存储开销,可以将不同的字符作为一个实例,每个字符实例都能根据外部传入的字体位置等信息进行绘图。

 

public interface Flyweight {
    public void draw(Pos pos, int fontsize);
}

public class Character implements Flyweight {
    private char _charcode;
    /**
     * 构造函数,内蕴状态作为参数传入
     * @param state
     */
    public Character(char c){
        this._charcode = char;
    }
    
    
    /**
     * 外蕴状态作为参数传入方法中,改变方法的行为,
     * 但是并不改变对象的内蕴状态。
     */
    @Override
    public void draw(Pos pos, int fontsize) {
        System.out.println(String.format("%d%d%d",pos.x,pos.y,fontsize));
    }

}

const int NCHARCODES = 128;
public class FlyweightFactory {
    private Character[] _chars = new Character[NCHARCODES];
    public FlyweightFactory(){
      for(int i=0; i<NCHARCODES; ++i){
        _chars[i]=null;
      }
    }
    public Flyweight factory(char c){
        if(_chars[c]==null){
            //如果对象不存在则创建一个新的Flyweight对象
            _chars[c] = new Character(c);
        }
        return _chars[c];
    }
}
class Program
    {

        static void Main(string[] args)
        {

            FlyweightFactory fac = new FlyweightFactory();
            Character curr = fac.factory('a');
            curr.show(new Pos(1,2),12);
            Console.Read();
        }
    }
View Code

 

7.代理模式

代理模式为其他对象提供一种代理以控制对这个对象的访问。

下面是一些需要使用代理的情形:

我们在对一个对象下达指令之前必须要先创建和初始化这个对象,对于一个比较大的对象,我们更倾向于在需要使用它的时候再去创建和初始化这个对象,我们将这个创建,初始化和使用对象的一系列操作都封装在了代理中。

我们需要对要访问的对象提供某种访问保护,这时我们将对象的权限验证和使用对象的一系列操作都封装在代理中。

namespace model
{
    abstract class Subject
    {
        public abstract void Request();
    }

    class RealSubject : Subject
    {
        public override void Request()
        {
            Console.WriteLine("真实的请求");
        }
    }

    class Proxy : Subject
    {
        RealSubject realSubject;
        public override void Request()
        {
            if (realSubject == null)
            {
                realSubject = new RealSubject();
            }

            realSubject.Request();
        }
    }
    class Program
    {

        static void Main(string[] args)
        {

            Proxy proxy = new Proxy();
            proxy.Request();
            Console.Read();
        }
    }
}
View Code

  使用代理的常见情况:

1)远程代理:为一个对象在不同的地址空间提供局部代表

2)虚代理:根据需要创建开销很大的对象

3)保护代理:控制对原始对象的访问

4)智能引用:取代了简单的指针,在访问对象时执行一些附加操作

 

 

 

posted @ 2013-11-04 19:44  Jingle Guo  阅读(4991)  评论(0编辑  收藏  举报