大话设计模式(二)代理模式 工厂方法模式 原型模式 模板方法模式 迪米特法模式 外观模式

代理模式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Proxy
{
    class Program
    {
        static void Main(string[] args)
        {
            SchoolGirl jiaojiao = new SchoolGirl();
            jiaojiao.Name = "李娇娇";

            Proxy daili = new Proxy(jiaojiao);

            daili.GiveDolls();
            daili.GiveFlowers();
            daili.GiveChocolate();



            ProxyDefine.Run.Go();
            Console.Read();
        }
    }

    //被追求者类
    class SchoolGirl
    {
        private string name;
        public string Name
        { set; get; }
    }
    //代理接口如下
    interface GiveGift
    {
        void GiveDolls();
        void GiveFlowers();
        void GiveChocolate();
    }

    //追求者类
    //唯一变化就是让“追求者”去实现“送礼物”接口
    class Pursuit : GiveGift
    {
        SchoolGirl mm;
        public Pursuit(SchoolGirl mm)
        {
            this.mm = mm;
        }
        public void GiveDolls()
        {
            Console.WriteLine(mm.Name + "送你洋娃娃");
        }

        public void GiveFlowers()
        {
            Console.WriteLine(mm.Name + "送你鲜花");
        }

        public void GiveChocolate()
        {
            Console.WriteLine(mm.Name + "送你巧克力");
        }
    }

    //代理类如下--让代理也去实现“送礼物”接口
    class Proxy : GiveGift
    {
        Pursuit gg;

        public Proxy(SchoolGirl mm)
        {
            gg = new Pursuit(mm);
        }
        public void GiveDolls()
        {
            gg.GiveDolls();
        }

        public void GiveFlowers()
        {
            gg.GiveFlowers();
        }

        public void GiveChocolate()
        {
            gg.GiveChocolate();
        }
    }

}

namespace ProxyDefine
{
    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();
        }
    }
    //客户端代码
    public class Run
    {
        public static void Go()
        {
            Proxy proxy = new Proxy();
            proxy.Request();
            Console.Read();
        }
    }
}

代理模式应用

使用代理模式的场景:

·远程代理,也就是为一个对象在不同的地址控件提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。(例如WebService)

·虚拟代理,根据需要创建开销很大的对象,通过他来存放实例化需要很长时间的真实对象。(浏览器加载图片)

·安全代理,用来控制真是对象访问时的权限。

·智能指引,是指当调用真实的对象时,代理处理另外一些事。

工厂方法模式

 

工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法把简单的工厂内部逻辑判断移到了客户端代码来进行,你想要加功能,本来是改工厂类,现在是改客户端。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Factory
{
    class Program
    {
        static void Main(string[] args)
        {
            //简单工厂模式
            LeiFeng studentA = SimpleFactory.CreateLeiFeng("学雷锋的大学生");
            studentA.BuyRice();
            LeiFeng studentB = SimpleFactory.CreateLeiFeng("学雷锋的大学生");
            studentB.Sweep();
            LeiFeng studentC = SimpleFactory.CreateLeiFeng("学雷锋的大学生");
            studentC.Wash();


            //工厂方法模式
            IFactory factory = new UndergraduateFactory();
            LeiFeng student = factory.CreateLeiFeng();
            student.BuyRice();
            student.Sweep();
            student.Wash();

            Console.Read();
        }
    }

    class LeiFeng
    {
        public void Sweep()
        {
            Console.WriteLine("扫地");
        }
        public void Wash()
        {
            Console.WriteLine("洗衣服");
        }

        public void BuyRice()
        {
            Console.WriteLine("买米");
        }
    }

    class Volunteer : LeiFeng
    { }

    //学雷锋的大学生继承雷锋
    class UnderGraduate : LeiFeng
    { }

    class SimpleFactory
    {
        public static LeiFeng CreateLeiFeng(string type)
        {
            LeiFeng result = null;
            switch (type)
            {
                case "学雷锋的大学生":
                    result = new UnderGraduate();
                    break;
                case "社区志愿者":
                    result = new Volunteer();
                    break;
                default:
                    break;
            }
            return result;
        }
    }

    //FactoryMethod
    interface IFactory
    {
        LeiFeng CreateLeiFeng();
    }

    //学雷锋的大学生工厂
    class UndergraduateFactory : IFactory
    {
        public LeiFeng CreateLeiFeng()
        {
            return new UnderGraduate();
        }
    }
    //志愿者的大学生工厂
    class VolunteerFactory : IFactory
    {

        public LeiFeng CreateLeiFeng()
        {
            return new Volunteer();
        }
    }
}

原型模式

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象在创建一个可定制的对象,而且不需要知道任何创建的细节。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Prototype
{
    class Program
    {
        static void Main(string[] args)
        {
            ConcretePrototype1 p1 = new ConcretePrototype1("I");
            //克隆类ConcretePrototype1的对象p1就能得到新的实例c1
            ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();

            Console.WriteLine("Cloned:{0}", c1.ID);
            Console.Read();
        }
    }
    //原型类
    abstract class Prototype
    {
        private string id;

        public Prototype(string id)
        {
            this.id = id;
        }

        public string ID
        {
            get 
            {
                return id;
            }
        }

        //抽象类关键就是有这样一个Clone方法
        public abstract Prototype Clone();
    }

    //具体原型类
    class ConcretePrototype1 : Prototype
    {
        public ConcretePrototype1(string id)
            : base(id)
        {

        }

        public override Prototype Clone()
        {
            /*创建当前 System.Object 的浅表副本。
             * 方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是之类型
             * 则对该字段执行逐位复制。如果字段是引用类型,则复制引用,但不复制引用的对象
             * 因此,原始对象及副本引用同一对象*/
            return (Prototype)this.MemberwiseClone();
        }
    }
}

浅复制与深复制

//浅复制
//被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。
namespace shallow_clone
{
    class WorkExperience
    {
        private string workDate;
        public string WorkDate
        {
            get;
            set;
        }

        private string company;
        public string Company
        {
            get;
            set;
        }
    }

    class Resume : ICloneable
    {
        private string name;
        private string sex;
        private string age;
        //引用“工作经历”对象
        private WorkExperience work;

        public Resume(string name)
        {
            this.name = name;
            //在“简历”类实例化时同时实例化“工作经历”
            work = new WorkExperience();
        }

        //设置个人信息
        public void SetPersonalInfo(string sex, string age)
        {
            this.sex = sex;
            this.age = age;
        }
        //设置工作经历
        public void SetWorkExperience(string workDate, string company)
        {
            //调用次方法给对象两个属性赋值
            work.WorkDate = workDate;
            work.Company = company;
        }

        public void Display()
        {
            Console.WriteLine("{0}{1}{2}", name, sex, age);
            Console.WriteLine("工作经历:{0}{1}", work.WorkDate, work.Company);
        }
        public Object Clone()
        {
            return (Object)this.MemberwiseClone();
        }
    }

    //客户端显示
    public class Run
    {
        public static void Go()
        {
            Resume a = new Resume("大鸟");
            a.SetPersonalInfo("", "29");
            a.SetWorkExperience("1998-2000", "xx公司");

            Resume b = (Resume)a.Clone();
            b.SetWorkExperience("1998-2005", "yy公司");

            Resume c = (Resume)a.Clone();
            c.SetWorkExperience("1998-2008", "zz公司");

            a.Display();
            b.Display();
            c.Display();

            Console.Read();
        }
    }
}

深复制

//深复制
//如果希望使用深复制(deep clone),必须自己实现自己期望的内容复制。
namespace deep_clone
{
    //让“工作经历”实现IConeable接口
    class WorkExperience : ICloneable
    {
        private string workDate;
        public string WorkDate
        {
            get { return workDate; }
            set { workDate = value; }
        }

        private string company;
        public string Company
        {
            get { return company; }
            set { company = value; }
        }

        public object Clone()
        {
            return (Object)this.MemberwiseClone();
        }
    }

    class Resume : ICloneable
    {
        private string name;
        private string sex;
        private string age;
        //引用“工作经历”对象
        private WorkExperience work;

        public Resume(string name)
        {
            this.name = name;
            //在“简历”类实例化时同时实例化“工作经历”
            work = new WorkExperience();
        }

        private Resume(WorkExperience work)
        {
            this.work = (WorkExperience)work.Clone();
        }

        //设置个人信息
        public void SetPersonalInfo(string sex, string age)
        {
            this.sex = sex;
            this.age = age;
        }
        //设置工作经历
        public void SetWorkExperience(string workDate, string company)
        {
            //调用次方法给对象两个属性赋值
            work.WorkDate = workDate;
            work.Company = company;
        }

        public void Display()
        {
            Console.WriteLine("{0}{1}{2}", name, sex, age);
            Console.WriteLine("工作经历:{0}{1}", work.WorkDate, work.Company);
        }
        public Object Clone()
        {
            Resume obj = new Resume(this.work);
            obj.name = this.name;
            obj.sex = this.sex;
            obj.age = this.age;
            return obj;
        }
    }

    //客户端显示
    public class Run
    {
        public static void Go()
        {
            Resume a = new Resume("大鸟");
            a.SetPersonalInfo("", "29");
            a.SetWorkExperience("1998-2000", "xx公司");

            Resume b = (Resume)a.Clone();
            b.SetWorkExperience("1998-2005", "yy公司");

            Resume c = (Resume)a.Clone();
            c.SetWorkExperience("1998-2008", "zz公司");

            a.Display();
            b.Display();
            c.Display();

            Console.Read();
        }
    }
}

模板方法模式

定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类这种。模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TemplateMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            AbstractClass c;
            c = new ConcreateClassA();
            c.TemplateMethod();

            c = new ConcreateClassB();
            c.TemplateMethod();

            Console.Read();
        }
    }

    abstract class AbstractClass
    {
        //一些抽象行为,放到子类去实现
        public abstract void PrimitiveOperation1();
        public abstract void PrimitiveOperation2();

        //模板方法,给出了逻辑的骨架而逻辑的组成是一些相应的抽象操作,他们推迟到子类实现
        public void TemplateMethod()
        {
            PrimitiveOperation1();
            PrimitiveOperation2();

            Console.WriteLine("");
        }
    }

    class ConcreateClassA : AbstractClass
    {

        public override void PrimitiveOperation1()
        {
            Console.WriteLine("具体A方法1实现");
        }

        public override void PrimitiveOperation2()
        {
            Console.WriteLine("具体A方法2实现");
        }
    }

    class ConcreateClassB : AbstractClass
    {

        public override void PrimitiveOperation1()
        {
            Console.WriteLine("具体B方法1实现");
        }

        public override void PrimitiveOperation2()
        {
            Console.WriteLine("具体B方法2实现");
        }
    }
}

模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现他的优势。它提供了一个很好的代码复用平台

使用情况:当不变得和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复不变行为的纠缠。

迪米特法则

如果两个类不必须彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

前提:在类的结构设计上,每一个类都应当尽量降低成员的访问权限。

迪米特法则根本思想是强调类之间的松耦合。我们在程序设计时,类之间的耦合越弱,越利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。

外观模式

 

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

代码模式:

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Facade
{
   
class Program
    {
       
static void Main(string[] args)
        {
            Facade facade
= new Facade();
            facade.MethodA();
            facade.MethodB();
            Console.Read();
        }
    }
   
class SubSystemOne
    {
       
public void MethodOne()
        {
            Console.WriteLine(
"子系统方法1");
        }
    }
   
class SubSystemTwo
    {
       
public void MethodTwo()
        {
            Console.WriteLine(
"子系统方法2");
        }
    }
   
class SubSystemThree
    {
       
public void MethodThree()
        {
            Console.WriteLine(
"子系统方法3");
        }
    }
   
class SubSystemFour
    {
       
public void MethodFour()
        {
            Console.WriteLine(
"子系统方法4");
        }
    }

   
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();
            three.MethodThree();
        }
       
public void MethodB()
        {
            Console.WriteLine(
"\n方法组B()----");
            three.MethodThree();
            four.MethodFour();
        }
    }
}

使用场景分三个阶段:

首先在设计初期阶段,应该要有意识的将不同的两个层分离(比如三层架构),层与层之间建立外观(Facade),这样可以为复杂的子系统提供一个简单的接口,使得耦合度降低。

其次,在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂。

第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了。这时候,可以用Facade为新系统开发一个外观的Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口(这句话真拗口),让系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。

posted @ 2014-02-10 09:52  无名の辈  阅读(585)  评论(0编辑  收藏  举报