大话设计模式(三)建造者模式 观察者模式 抽象工厂模式 状态模式 适配器模式 备忘录模式

建造者模式

建造者模式(Builder):将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式的一个实例代码:

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

namespace Builder
{
    abstract class PersonBuilder
    {
        protected Graphics g;
        protected Pen p;

        public PersonBuilder(Graphics g, Pen p)
        {
            this.g = g;
            this.p = p;
        }

        public abstract void BuildHead();
        public abstract void BuildBody();
        public abstract void BuildArmLeft();
        public abstract void BuildArmRight();
        public abstract void BuildLegLeft();
        public abstract void BuildLegRight();
    }

    //一个瘦子
    class PersonThinBuilder : PersonBuilder
    {
        public PersonThinBuilder(Graphics g, Pen p)
            : base(g, p)
        {

        }
        public override void BuildHead()
        {
            g.DrawEllipse(p, 50, 20, 30, 30);
        }

        public override void BuildBody()
        {
            g.DrawRectangle(p, 60, 50, 10, 50);
        }

        public override void BuildArmLeft()
        {
            g.DrawLine(p, 60, 50, 40, 100);
        }

        public override void BuildArmRight()
        {
            g.DrawLine(p, 70, 50, 90, 100);
        }

        public override void BuildLegLeft()
        {
            g.DrawLine(p, 60, 100, 45, 150);
        }

        public override void BuildLegRight()
        {
            g.DrawLine(p, 70, 100, 85, 150);
        }
    }

    //指挥者(Director)
    class PersonDirector
    {
        private PersonBuilder pb;
        //用户告诉指挥官我要什么样的人
        public PersonDirector(PersonBuilder pb)
        {
            this.pb = pb;
        }
        //根据用户的选择建造小人
        public void createPerson()
        {
            pb.BuildHead();
            pb.BuildArmLeft();
            pb.BuildArmRight();
            pb.BuildBody();
            pb.BuildLegLeft();
            pb.BuildLegRight();
        }
    }
}
//客户端代码
Pen p = new Pen(Color.Blue);
PersonThinBuilder ptb = new PersonThinBuilder(pictureBox1.CreateGraphics(), p);
PersonDirector pdThin = new PersonDirector(ptb);
pdThin.createPerson();

观察者模式

观察者模式:定义一种一对多的依赖关系,让多个观察者对象同事监听某一个主题对象。这个主题对象在状态发生变化时,会通过所有观察者对象,使他们能够自动更新自己。

实例代码:

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

namespace Observer
{
    class Program
    {
        static void Main(string[] args)
        {
            Observer_Demo.Run.Go();
        }
    }
}
namespace Observer_Demo
{
    abstract class Subject
    {
        private IList<Observer> observers = new List<Observer>();

        //增加观察者
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }
        //删除观察者
        public void Detach(Observer observer)
        {
            observers.Remove(observer);
        }

        //通知
        public void Notify()
        {
            foreach (Observer o in observers)
            {
                o.Update();
            }
        }
    }

    abstract class Observer
    {
        public abstract void Update();
    }

    //具体的通知者
    class ConcreteSubject : Subject
    {
        private string subjectState;
        //具体被观察者状态
        public string SubjectState
        {
            get { return subjectState; }
            set { subjectState = value; }
        }
    }

    //具体观察者
    class ConcreteObserver : Observer
    {
        private string name;
        private string observerState;
        private ConcreteSubject subject;

        public ConcreteObserver(ConcreteSubject subject, string name)
        {
            this.subject = subject;
            this.name = name;
        }
        public override void Update()
        {
            observerState = subject.SubjectState;
            Console.WriteLine("观察者模式{0}的新状态是{1}", name, observerState);
        }

        public ConcreteSubject Subject
        {
            get { return subject; }
            set { subject = value; }
        }
    }

    public class Run
    {
        public static void Go()
        {
            ConcreteSubject s = new ConcreteSubject();

            s.Attach(new ConcreteObserver(s, "X"));
            s.Attach(new ConcreteObserver(s, "Y"));
            s.Attach(new ConcreteObserver(s, "Z"));

            s.SubjectState = "ABC";
            s.Notify();

            Console.Read();
        }
    }
}

观察者模式的动机:将一个系统分割成一系列相互协作的类,有一个很不好的副作用,那就是需要维护相关对象见间的一致性。我们不希望为了维持一致性而是各类紧密耦合,这样会给维护、扩展和重用都带来不便。

使用场景:当一个对象的改变需要同时改变其他对象,而且他不知道具体有多少对象有待改变时,应该考虑使用观察者模式。当一个抽象模型有两个方面,其中一个方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使他们各自独立的改变和复用。总的来说,观察者模式所做的工作其实就是在接触耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。

事件委托

namespace Observer_delegate
{
    class StockObserver
    {
        private string name;
        private Subject sub;

        public StockObserver(string name, Subject sub)
        {
            this.name = name;
            this.sub = sub;
        }

        //关闭股票行情
        public void CloseStockMarket()
        {
            Console.WriteLine("{0} {1}关闭股票行情,继续工作", sub.SubjectState, name);
        }
    }

    class NBAObserver
    {
        private string name;
        private Subject sub;

        public NBAObserver(string name, Subject sub)
        {
            this.name = name;
            this.sub = sub;
        }

        //关闭股票行情
        public void CloseNBADirectSeeding()
        {
            Console.WriteLine("{0} {1}关闭NBA直播,继续工作", sub.SubjectState, name);
        }
    }

    interface Subject
    {
        void Notify();

        string SubjectState
        { get; set; }
    }

    delegate void EventHandler();
    class Boss : Subject
    {
        //声明一个事件Update,类型为委托EventHandler
        public event EventHandler Update;

        private string action;

        public void Notify()
        {
            Update();
        }

        public string SubjectState
        {
            get { return action; }
            set { action = value; }
        }
    }
    class Secretary : Subject
    {
        //与老板类实现类似
        //声明一个事件Update,类型为委托EventHandler
        public event EventHandler Update;

        private string action;

        public void Notify()
        {
            Update();
        }

        public string SubjectState
        {
            get { return action; }
            set { action = value; }
        }
    }

    public class Run
    {
        public static void Go()
        {
            //老板胡汉三
            Boss huhansan = new Boss();

            //看股票的同事
            StockObserver Tongshi1 = new StockObserver("aa", huhansan);

            NBAObserver Tongshi2 = new NBAObserver("bb", huhansan);
            /*将“看股票着”的“关闭股票程序”方法和“看NBA者”的“关闭NBA直播”
             *方法挂钩到“老板”的更新上,也就是将两个不同类的不同方法委托给“老板”
             *类的“更新”了
             */
            huhansan.Update += new EventHandler(Tongshi1.CloseStockMarket);
            huhansan.Update += new EventHandler(Tongshi2.CloseNBADirectSeeding);

            //老板 回来了
            huhansan.SubjectState = "我胡汉三回来啦";
            huhansan.Notify();

            Console.Read();
        }
    }
}

现在可以解释一下什么事委托了:

委托就是一种引用方法的类型,一旦为委托分配了方法,委托将于该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,如有参数和返回值,委托可以看作是对函数的抽象,是函数的’类‘,委托的实例将代表一个具体的函数。

抽象工厂模式

先来一个实例:

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

namespace Abstract_Factory
{
    class Program
    {
        static void Main(string[] args)
        {
            Abstract_Factory_DB.Run.Go();
        }
    }
}
namespace Abstract_Factory_DB
{
    class Department
    {
        private int _id;
        public int ID
        {
            get { return _id; }
            set { _id = value; }
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
    }

    //IDepartment接口,用于访问客户端访问,解除与具体数据库访问的耦合
    interface IDepartment
    {
        void insert(Department department);
        Department GetDepartment(int id);
    }

    class SqlserverDepartment : IDepartment
    {

        public void insert(Department department)
        {
            Console.WriteLine("在SQL中加入一条数据");
        }

        public Department GetDepartment(int id)
        {
            Console.WriteLine("在SQL中得到一条数据");
            return null;
        }
    }
    class AccessDepartment : IDepartment
    {

        public void insert(Department department)
        {
            Console.WriteLine("在Access中加入一条数据");
        }

        public Department GetDepartment(int id)
        {
            Console.WriteLine("在Access中得到一条数据");
            return null;
        }
    }

    //IFactory接口,定义一个穿件访问Department表对象的抽象的工厂接口

    interface IFactory
    {
        //增加接口的方法
        IDepartment CeateDepartment();
    }

    class SqlServerFactory : IFactory
    {

        public IDepartment CeateDepartment()
        {
            return new SqlserverDepartment();
        }
    }

    class AccessFactory : IFactory
    {

        public IDepartment CeateDepartment()
        {
            return new AccessDepartment();
        }
    }

    //客户端代码:
    public class Run
    {
        public static void Go()
        {
            Department dept = new Department();

            //则此时已与具体数据库访问解除了依赖
            //IFactory factorysql = new SqlServerFactory();
            IFactory factory = new AccessFactory();

            IDepartment idept = factory.CeateDepartment();
            idept.insert(dept);
            idept.GetDepartment(1);
            Console.Read();
        }
    }
}

抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。

QQ图片20131118170442

IFactory是一个抽象工厂接口,他里面应该包含所有的产品创建的抽象方法。

通常是运行时刻再创建一个ConcreteFactory类的实例,这个具体的工厂在创建具有特定实现的产品对象,也就是说,为创建不同的产品对象,客户端应使用不同的具体工厂。

抽象工厂模式的优点:

易于交换产品系列,犹豫具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,他只需要改变具体工厂即可使用不同的产品配置。

它让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。

用简单工厂来改进抽象工厂

class DataAccess
    {
        private static readonly string db = "Sqlserver";

        public static IDepartment CreateDepartment()
        {
            IDepartment result = null;
            switch (db)
            {
                case "Sqlserver":
                    result = new SqlserverDepartment();
                    break;
                case "Access":
                    result = new AccessDepartment();
                    break;
                default:
                    break;
            }
            return result;
        }
    }

    public class Simple_Abstract_Factory
    {
        public static void Go()
        {
            Department dept = new Department();

            IDepartment idept = DataAccess.CreateDepartment();
            idept.insert(dept);
            idept.GetDepartment(1);
            Console.Read();
        }
    }

用反射+抽象工厂的数据访问程序

依赖注入(Dependency Injection)

反射技术的格式:Assembly.Load(“程序集名称”).CreateInstance(“命名空间.类名称”)

//用反射+配置文件实现数据库访问程序集
    class DataAccess_Reflection
    {
        //程序集名称
        private static readonly string AssemblyName = "Abstract_Factory_DB";
        //数据库名称,可替换成Access
        private static readonly string db = ConfigurationManager.AppSettings["DB"];

        public static IDepartment CreateDepartment()
        {
            
            string className = AssemblyName + "." + db + "Department";
            return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
        }
    }

但是这里面我加入到我的代码中运行却出现错误,CreateDepartment() 返回的是一个null,有哪位大神知道的顺便和咱这菜鸟说说。

状态模式

状态模式(State):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同的一系列类当中,可以把复杂的判断逻辑简化。

image

先来一个小Demo

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

namespace State
{
    class Program
    {
        static void Main(string[] args)
        {
            Context c = new Context(new ConcreteStateA());
            c.Request();
            c.Request();
            c.Request();
            c.Request();

            Console.Read();
        }
    }
    //定义一个接口与Context的一个特定状态相关的行为
    abstract class State
    {
        //Context--为驻留在其中的对象定义环境,在此环境中可以实施策略。
        public abstract void Handle(Context context);
    }
    //具体状态,每个子类实现一个与Context的一个状态相关的行为
    class ConcreteStateA : State
    {

        public override void Handle(Context context)
        {
            context.State = new ConcreteStateB();
        }
    }
    class ConcreteStateB : State
    {

        public override void Handle(Context context)
        {
            context.State = new ConcreteStateA();
        }
    }
    //维护一个ConcreteState子类的实例,这个实例定义当前状态
    class Context
    {
        private State state;
        public Context(State state)
        {
            this.state = state;
        }
        public State State
        {
            get { return state; }
            set
            {
                state = value;
                Console.WriteLine("当前状态:" + state.GetType().Name);
            }
        }
        public void Request()
        {
            //对请求做处理,并设置下一状态
            state.Handle(this);
        }

    }
}

状态模式的好处和用处:

状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。将特定状态相关的行为放入一个对象中,由于所有与状态相关的代码都存在某个ConcreteState中,所以通过定义新的子类可以很容易增加新的状态和转换。从而消除庞大的条件语句。状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖

使用场景:当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变他的行为时,就可以考虑使用状态模式了。

工作状态的状态模式版本:

namespace WorkState
{
    public abstract class State
    {
        public abstract void WriteProgram(Work w);
    }

    public class ForenoonState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 12)
            {
                Console.WriteLine("当前时间:{0}点 上午工作,精神百倍", w.Hour);
            }
            else
            {
                w.SetState(new noonState());
                w.WriteProgram();
            }
        }
    }

    public class noonState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 13)
            {
                Console.WriteLine("当前时间:{0}点 饿了,午饭:犯困,午休", w.Hour);
            }
            else
            {
                w.SetState(new AfternoonState());
                w.WriteProgram();
            }
        }
    }

    public class AfternoonState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 17)
            {
                Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力", w.Hour);
            }
            else
            {
                w.SetState(new EveningState());
                w.WriteProgram();
            }
        }
    }

    public class EveningState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.TaskFinshed)
            {
                //如果完成任务则下班状态
                w.SetState(new RestState());
            }
            else
            {
                if (w.Hour < 21)
                {
                    Console.WriteLine("当前时间{0}点,加班哦疲惫之极", w.Hour);
                }
                else
                {
                    w.SetState(new SleepingState());
                    w.WriteProgram();
                }
            }
        }
    }

    public class SleepingState : State
    {

        public override void WriteProgram(Work w)
        {
            Console.WriteLine("当前时间{0}点不行了,睡着了", w.Hour);
        }
    }

    public class RestState : State
    {

        public override void WriteProgram(Work w)
        {
            Console.WriteLine("当前时间{0}点下班回家了", w.Hour);
        }
    }
    public class Work
    {
        private State current;
        public Work()
        {
            current = new ForenoonState();
        }

        private double hour;
        public double Hour
        {
            get { return hour; }
            set { this.hour = value; }
        }

        private bool finish = false;
        public bool TaskFinshed
        {
            get { return finish; }
            set { this.finish = value; }
        }

        public void SetState(State e)
        {
            current = e;
        }

        public void WriteProgram()
        {
            current.WriteProgram(this);
        }
    }
    public class Run
    {
        public static void Go()
        {
            Work emergencyProjects = new Work();
            emergencyProjects.Hour = 9;
            emergencyProjects.WriteProgram();
            emergencyProjects.Hour = 10;
            emergencyProjects.WriteProgram();
            emergencyProjects.Hour = 12;
            emergencyProjects.WriteProgram();
            emergencyProjects.Hour = 14;
            emergencyProjects.WriteProgram();
            emergencyProjects.Hour = 17;
            emergencyProjects.WriteProgram();

            emergencyProjects.TaskFinshed = false;

            emergencyProjects.WriteProgram();
            emergencyProjects.Hour = 19;
            emergencyProjects.WriteProgram();
            emergencyProjects.Hour = 22;
            emergencyProjects.WriteProgram();

            Console.Read();

        }
    }
}

适配器模式

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

使用情况:系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。

image

根据这个结构图,我们写出如下的Demo

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

namespace Adapter
{
    class Program
    {
        static void Main(string[] args)
        {
            Target target = new Adapter();
            target.Request();

            Console.Read();
        }
    }
    //这是客户所期待的接口,目标可以是具体的或抽象的类,也可以是接口
    class Target
    {
        public virtual void Request()
        {
            Console.WriteLine("普通请求");
        }
    }
    //要适配的类
    class Adaptee
    {
        public void SpecificRequest()
        {
            Console.WriteLine("特殊请求!");
        }
    }
    class Adapter : Target
    {
        //建立一个私有的Adapter对象
        private Adaptee adaptee = new Adaptee();

        //这样就可以把表面上调用Request()方法变成实际调用SpecificRequest()
        public override void Request()
        {
            adaptee.SpecificRequest();
        }
    }
}

适配器模式的.NET应用:DataAdapter用作DataSet和数据源之间的适配器以便检索和保存数据。DataAdapter通过Fill(这更改了DataSet中的数据以便于数据源中的数据相匹配)和Update来提供这一适配器。

备忘录模式

Memento:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态

image

针对结构图的一个代码demo

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

namespace Memento
{
    class Program
    {
        static void Main(string[] args)
        {
            Originator o = new Originator();

            o.State = "on";
            o.Show();

            Caretaker c = new Caretaker();
            c.Memento = o.CreateMemento();

            o.State = "Off";
            o.Show();

            o.SetMemento(c.Memento);
            o.Show();

            Console.Read();
        }
    }
    //发起人
    class Originator
    {
        private string state;
        public string State
        {
            get { return state; }
            set { this.state = value; }
        }
        //创建备忘录,将当前需要保存的信息导入并实例化出一个Memento对象
        public Memento CreateMemento()
        {
            return (new Memento(state));
        }
        public void SetMemento(Memento memento)
        {
            state = memento.State;
        }

        public void Show()
        {
            Console.WriteLine("State=" + state);
        }
    }

    //备忘录
    class Memento
    {
        private string state;

        public Memento(string state)
        {
            this.state = state;
        }
        public string State
        {
            get { return state; }
        }
    }

    //管理者
    class Caretaker
    {
        private Memento memento;

        public Memento Memento
        {
            get { return memento; }
            set { memento = value; }
        }
    }

}

备忘录模式就是把保存的细节给封装在Memento中了,那一天要改变保存的细节也不能影响客户端。

Memento模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存属性只是众多属性中的一小部分,Originator可以根据保存的Memento信息还原到前一个状态。

如果在某个系统中使用命令模式时,需要实现命令的撤销功能,那么命令莫斯可以使用备忘录模式来存储可撤销错做的状态。使用备忘录可以把复杂的对象内部信息对其他的对象屏蔽起来。

当角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原

原文地址:https://www.cnblogs.com/sunhan/p/3542326.html