【设计模式】——结构型

适配器模式(Adapter)

将一个类的借口转换成客户希望的另外一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

解释:大家都知道,我们国家规定的各种用电电压是220V,我们的电视能直接通220V电压工作,这个时候220V电压和电视就能兼容(正常工作),但是手机,笔记本这些电子设备的工作电压远远低于220V电压,我们如何让他们正常工作呢?这个时候让国家把电压降低明显是不可能的,况且不同的设备都有自己的工作电压,那就是用一个充电器或者适配器,让220V的电压通过充电器或者电源适配器后变成手机,笔记本等设备的工作电压,这样原来不能直接工作的220V电压和手机,笔记本就可以兼容了。


//适配者Adaptee
    //一般是一个具体的类,包含了客户端想要的业务方法
    //由于C#不支持多重继承,所以类适配器模式中Target只能为接口
    public class Adaptee
    {
        public void RequestSample()
        {
            Console.WriteLine("我是适配者类!");
        }
    }
//适配器Adapter
    public class Adapter:Target
    {
        private Adaptee a = new Adaptee();
        public override void Request()
        {
            a.RequestSample();
        }
    }
//目标抽象类Target
    public class Target
    {
        public virtual void Request();
    }
//客户端
    //获取适配器名称
    Target t = new Adapter;
    t.Request();
    Console.ReadLine();

—————————————————————————————————————————————————————

装饰模式(Decorator)

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

解释:装饰模式,简而言之就是给一件东西进行外表的装饰,但是并没有改变东西的本质。


    // 手机抽象类,即装饰者模式中的抽象组件类
    public abstract class Phone
    {
        public abstract void Print();
    }
    // 苹果手机,即装饰着模式中的具体组件类
    public class ApplePhone:Phone
    {
        public override void Print()
        {
            Console.WriteLine("开始执行具体的对象——苹果手机");
        }
    }
    // 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Phone
    public abstract class Decorator:Phone
    {
        private Phone phone;

        public Decorator(Phone p)
        {
            this.phone = p;
        }

        public override void Print()
        {
            if (phone != null)
            {
                phone.Print();
            }
        }
    }
    // 贴膜,即具体装饰者
    public class Sticker : Decorator
    {
        public Sticker(Phone p)
            : base(p)
        { 
        }

        public override void Print()
        {
            base.Print();
            // 添加新的行为
            AddSticker();      
        }

        // 新的行为方法
        public void AddSticker()
        {
            Console.WriteLine("现在苹果手机有贴膜了");
        }
    }

    // 手机挂件
    public class Accessories : Decorator
    {
        public Accessories(Phone p)
            : base(p)
        {
        }

        public override void Print()
        {
            base.Print();
            // 添加新的行为
            AddAccessories();          
        }

        /// 新的行为方法
        public void AddAccessories()
        {
            Console.WriteLine("现在苹果手机有漂亮的挂件了");
        }
    }
//客户端
            // 我买了个苹果手机
            Phone phone = new ApplePhone();

            // 现在想贴膜了
            Decorator applePhoneWithSticker = new Sticker(phone);
            // 扩展贴膜行为
            applePhoneWithSticker.Print();
            Console.WriteLine("----------------------\n");

            // 现在我想有挂件了
            Decorator applePhoneWithAccessories = new Accessories(phone);
            // 扩展手机挂件行为
            applePhoneWithAccessories.Print();
            Console.WriteLine("----------------------\n");

            // 现在我同时有贴膜和手机挂件了
            Sticker sticker = new Sticker(phone);
            Accessories applePhoneWithAccessoriesAndSticker = new Accessories(sticker);
            applePhoneWithAccessoriesAndSticker.Print();
            Console.ReadLine();        

—————————————————————————————————————————————————————

桥接模式(Bridge)

将抽象(Abstraction:存在于多个实体中的共同的概念性联系)部分与它的现实(Implementation:抽象化给出的具体实现,即为实现化)部分分离,使它们都可以独立的变化。

解释:如果一个抽象类或接口有多个具体实现子类,而这些子类之中有内容或概念上重叠,需要我们把抽象的共同部分各自独立开来:即原来是准备放在一个接口里,现在需要设计两个接口——抽象接口和行为接口。然后再分别针对各自的具体子类定义抽象接口和行为接口的方法和调用关系。


    // 电视机,提供抽象方法
    public abstract class TV
    {
        public abstract void On();
        public abstract void Off();
        public abstract void tuneChannel();
    }
    // 三星牌电视机,重写基类的抽象方法
    public class Samsung:TV
    {
        public override void On()
        {
            Console.WriteLine("三星牌电视机已经打开了");
        }
 
        public override void Off()
        {
            Console.WriteLine("三星牌电视机已经关掉了");
        }
 
        public override void tuneChannel()
        {
            Console.WriteLine("三星牌电视机换频道");
        }
    }
 
    // 长虹牌电视机,重写基类的抽象方法
    // 提供具体的实现
    public class ChangHong : TV
    {
        public override void On()
        {
            Console.WriteLine("长虹牌电视机已经打开了");
        }
 
        public override void Off()
        {
            Console.WriteLine("长虹牌电视机已经关掉了");
        }
 
        public override void tuneChannel()
        {
            Console.WriteLine("长虹牌电视机换频道");
        }
    }
    //  抽象概念中的遥控器,扮演抽象化角色
    public abstract class RemoteControl
    {
        public TV implementor { get; set; }
 
        // 开电视机
        // 这里抽象类中不再提供实现了,而是调用实现类中的实现
        public virtual void On()
        {
            implementor.On();
        }
 
        // 关电视机
        public virtual void Off()
        {
            implementor.Off();
        }
 
        // 换频道
        public virtual void SetChannel()
        {
            implementor.tuneChannel();
        }
    }
    // 具体遥控器类
    public class ConcreteRemote:RemoteControl
    {
        // 重写更换频道方法
        public override void SetChannel()
        {
            Console.WriteLine("重写更换频道方法");
            base.SetChannel();
        }
    }
//客户端
            // 创建一个遥控器
            RemoteControl remoteControl = new ConcreteRemote();
            
            //长虹电视机
            remoteControl.implementor = new ChangHong();
            remoteControl.On();
            remoteControl.SetChannel();
            remoteControl.Off();
            Console.WriteLine();
 
            // 三星牌电视机
            remoteControl.implementor = new Samsung();
            remoteControl.On();
            remoteControl.SetChannel();
            remoteControl.Off();
            Console.Read();        

—————————————————————————————————————————————————————

组合模式(Composite)

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

解释:在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象在功能上区别,导致在操作过程中必须区分简单对象和复合对象,这样就会导致客户调用带来不必要的麻烦,然而作为客户,它们希望能够始终一致地对待简单对象和复合对象。然而组合模式就是解决这样的问题。


//透明式的组合模式的实现

    
    // 该抽象类就是文件夹抽象接口的定义,该类型就相当于是抽象构件Component类型
    
    public abstract class Folder
    {
        //增加文件夹或文件
        public abstract void Add(Folder folder);

        //删除文件夹或者文件
        public abstract void Remove(Folder folder);

        //打开文件或者文件夹--该操作相当于Component类型的Operation方法
        public abstract void Open();
    }
    // 该Word文档类就是叶子构件的定义,该类型就相当于是Leaf类型,不能在包含子对象
    
    public sealed class Word : Folder
    {
        //增加文件夹或文件
        public override void Add(Folder folder)
        {
            throw new Exception("Word文档不具有该功能");
        }

        //删除文件夹或者文件
        public override void Remove(Folder folder)
        {
            throw new Exception("Word文档不具有该功能");
        }

        //打开文件--该操作相当于Component类型的Operation方法
        public override void Open()
        {
            Console.WriteLine("打开Word文档,开始进行编辑");
        }
    }

    
    // SonFolder类型就是树枝构件,由于我们使用的是“透明式”,所以Add,Remove都是从Folder类型继承下来的
    
    public class SonFolder : Folder
    {
        //增加文件夹或文件
        public override void Add(Folder folder)
        {
            Console.WriteLine("文件或者文件夹已经增加成功");
        }

        //删除文件夹或者文件
        public override void Remove(Folder folder)
        {
            Console.WriteLine("文件或者文件夹已经删除成功");
        }

        //打开文件夹--该操作相当于Component类型的Operation方法
        public override void Open()
        {
            Console.WriteLine("已经打开当前文件夹");
        }
    }
//客户端
            Folder myword = new Word();

            myword.Open();//打开文件,处理文件

            myword.Add(new SonFolder());//抛出异常
            myword.Remove(new SonFolder());//抛出异常


            Folder myfolder = new SonFolder();
            myfolder.Open();//打开文件夹

            myfolder.Add(new SonFolder());//成功增加文件或者文件夹
            myfolder.Remove(new SonFolder());//成功删除文件或者文件夹

            Console.Read();
// 安全式的组合模式的实现

    // 该抽象类就是文件夹抽象接口的定义,该类型就相当于是抽象构件Component类型
    
    public abstract class Folder //该类型少了容器对象管理子对象的方法的定义,换了地方,在树枝构件也就是SonFolder类型
    {
        //打开文件或者文件夹--该操作相当于Component类型的Operation方法
        public abstract void Open();
    }
    // 该Word文档类就是叶子构件的定义,该类型就相当于是Leaf类型,不能在包含子对象

    public sealed class Word : Folder  //这类型现在很干净
    {
        //打开文件--该操作相当于Component类型的Operation方法
        public override void Open()
        {
            Console.WriteLine("打开Word文档,开始进行编辑");
        }
    }

    // SonFolder类型就是树枝构件,现在由于我们使用的是“安全式”,所以Add,Remove都是从此处开始定义的
    public abstract class SonFolder : Folder //这里可以是抽象接口,可以自己根据自己的情况而定
    {
        //增加文件夹或文件
        public abstract void Add(Folder folder);

        //删除文件夹或者文件
        public abstract void Remove(Folder folder);

        //打开文件夹--该操作相当于Component类型的Operation方法
        public override void Open()
        {
            Console.WriteLine("已经打开当前文件夹");
        }
    }

    
    // NextFolder类型就是树枝构件的实现类
    
    public sealed class NextFolder : SonFolder
    {
        //增加文件夹或文件
        public override void Add(Folder folder)
        {
            Console.WriteLine("文件或者文件夹已经增加成功");
        }

        //删除文件夹或者文件
        public override void Remove(Folder folder)
        {
            Console.WriteLine("文件或者文件夹已经删除成功");
        }

        //打开文件夹--该操作相当于Component类型的Operation方法
        public override void Open()
        {
            Console.WriteLine("已经打开当前文件夹");
        }
    }

//客户端
            //这是安全的组合模式
            Folder myword = new Word();

            myword.Open();//打开文件,处理文件

            Folder myfolder = new NextFolder();
            myfolder.Open();//打开文件夹

            //此处要是用增加和删除功能,需要转型的操作,否则不能使用
            ((SonFolder)myfolder).Add(new NextFolder());//成功增加文件或者文件夹
            ((SonFolder)myfolder).Remove(new NextFolder());//成功删除文件或者文件夹

            Console.Read();

—————————————————————————————————————————————————————

享元模式(flyweight)

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

解释:在软件开发过程,如果我们需要重复使用某个对象的时候,如果我们重复地使用new创建这个对象的话,这样我们在内存就需要多次地去申请内存空间了,这样可能会出现内存使用越来越多的情况,这样的问题是非常严重。

享元模式可以避免大量相似类的开销,在软件开发中如果需要生成大量细粒度的类实例来表示数据,如果这些实例除了几个参数外基本上都是相同的,这时候就可以使用享元模式来大幅度减少需要实例化类的数量。如果能把这些参数(指的这些类实例不同的参数)移动类实例外面,在方法调用时将他们传递进来,这样就可以通过共享大幅度地减少单个实例的数目。

内部状态:在享元对象的内部并且不会随着环境的改变而改变的共享部分

外部状态:随环境改变而改变的,不可以共享的状态。


一个文本编辑器中会出现很多字面,使用享元模式去实现这个文本编辑器的话,会把每个字面做成一个享元对象。享元对象的内部状态就是这个字面,而字母在文本中的位置和字体风格等其他信息就是它的外部状态。下面就以这个例子来实现下享元模式,具体实现代码如下:

    // 抽象享元类,提供具体享元类具有的方法
    
    public abstract class Flyweight
    {
        public abstract void Operation(int extrinsicstate);
    }
    // 具体的享元对象,这样我们不把每个字母设计成一个单独的类了,而是作为把共享的字母作为享元对象的内部状态
    
    public class ConcreteFlyweight : Flyweight
    {
        // 内部状态
        private string intrinsicstate;

        // 构造函数
        public ConcreteFlyweight(string innerState)
        {
            this.intrinsicstate = innerState;
        }

        
        // 享元类的实例方法        
        // <param name="extrinsicstate">外部状态</param>
        public override void Operation(int extrinsicstate)
        {
            Console.WriteLine("具体实现类: intrinsicstate {0}, extrinsicstate {1}", intrinsicstate, extrinsicstate);
        }
    }
    // 享元工厂,负责创建和管理享元对象

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

        public FlyweightFactory()
        {
            flyweights.Add("A", new ConcreteFlyweight("A"));
            flyweights.Add("B", new ConcreteFlyweight("B"));
            flyweights.Add("C", new ConcreteFlyweight("C"));
        }

        public Flyweight GetFlyweight(string key)
        {
            return flyweights[key] as Flyweight;
        }
    }
//客户端
static void Main(string[] args)
        {
            // 定义外部状态,例如字母的位置等信息
            int externalstate = 10;
            // 初始化享元工厂
            FlyweightFactory factory = new FlyweightFactory();

            // 判断是否已经创建了字母A,如果已经创建就直接使用创建的对象A
            Flyweight fa = factory.GetFlyweight("A");
            if (fa != null)
            {
                // 把外部状态作为享元对象的方法调用参数
                fa.Operation(--externalstate);
            }
            // 判断是否已经创建了字母B
            Flyweight fb = factory.GetFlyweight("B");
            if (fb != null)
            {
                fb.Operation(--externalstate);
            }
            // 判断是否已经创建了字母C
            Flyweight fc = factory.GetFlyweight("C");
            if (fc != null)
            {
                fc.Operation(--externalstate);
            }
            // 判断是否已经创建了字母D
            Flyweight fd = factory.GetFlyweight("D");
            if (fd != null)
            {
                fd.Operation(--externalstate);
            }
            else
            {
                Console.WriteLine("驻留池中不存在字符串D");
                // 这时候就需要创建一个对象并放入驻留池中
                ConcreteFlyweight d = new ConcreteFlyweight("D");
                factory.flyweights.Add("D", d);
            }

            Console.Read();
        }

—————————————————————————————————————————————————————

代理模式(Proxy)

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

解释:在现实生活中,如果有同事出国或者朋友出国的情况下,我们经常会拖这位朋友帮忙带一些电子产品或化妆品等东西,这个场景中,出国的朋友就是一个代理,他是他朋友的一个代理,由于他朋友不能去国外买东西,他却可以,所以朋友们都托他帮忙带一些东西的。


// 客户端调用
    class Client
    {
        static void Main(string[] args)
        {
            // 创建一个代理对象并发出请求
            Person proxy = new Friend();
            proxy.BuyProduct();
            Console.Read();
        }
    }
    // 抽象主题角色
    public abstract class Person
    {
        public abstract void BuyProduct();
    }
    //真实主题角色
    public class RealBuyPerson : Person
    {
        public override void BuyProduct()
        {
            Console.WriteLine("帮我买一个IPhone和一台苹果电脑");
        }
    }
    // 代理角色
    public class Friend:Person
    {
        // 引用真实主题实例
        RealBuyPerson realSubject;

        public override void BuyProduct()
        {
            Console.WriteLine("通过代理类访问真实实体对象的方法");
            if (realSubject == null)
            {
                realSubject = new RealBuyPerson();
            }

            this.PreBuyProduct();
            // 调用真实主题方法
            realSubject.BuyProduct();
            this.PostBuyProduct();
        }

        // 代理角色执行的一些操作
        public void PreBuyProduct()
        {
            // 可能不知一个朋友叫这位朋友带东西,首先这位出国的朋友要对每一位朋友要带的东西列一个清单等
            Console.WriteLine("我怕弄糊涂了,需要列一张清单,张三:要带相机,李四:要带Iphone...........");
        }
        
        // 买完东西之后,代理角色需要针对每位朋友需要的对买来的东西进行分类
        public void PostBuyProduct()
        {
            Console.WriteLine("终于买完了,现在要对东西分一下,相机是张三的;Iphone是李四的..........");
        }
    }

—————————————————————————————————————————————————————

外观模式(Facade)

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

解释:由外观类去保存各个子系统的引用,实现由一个统一的外观类去包装多个子系统类,然而客户端只需要引用这个外观类,然后由外观类来调用各个子系统中的方法。这样的实现方式非常类似适配器模式,然而外观模式与适配器模式不同的是:适配器模式是将一个对象包装起来以改变其接口,外观是将一群对象 ”包装“起来以简化其接口。其意图是不一样的,适配器是将接口转换为不同接口,而外观模式是提供一个统一的接口来简化接口。


//客户端
            Fund jijin = new Fund();
            //购买基金
            jijin.BuyFund();
            //基金赎回
            jijin.SellFund();
            Console.Read();
//子系统
    class Stock1
    {
        public void Sell()
        {
            Console.WriteLine("股票1卖出");
        }
        public void Buy()
        {
            Console.WriteLine("股票1买入");
        }
    }
   //其他的类似就省略了
//门面
    
    //基金
    class Fund
    {
        Stock1 gu1;

        public Fund()
        {
            gu1 = new Stock1();
        }
        public void BuyFund()
        {
            gu1.Buy();
        }
        public void SellFund()
        {
            gu1.Sell();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/mirabellezwh/article/details/80874617
今日推荐