设计模式

原创 2015年07月09日 11:24:35

最近在看设计模式 记录一下

观察者模式:类似与安卓里面的一个button 设置不同的listerner

装饰着模式:java i/O里面 filterinputstream 修饰inputstream bufferedinputstream修饰filterinputstream 


观察者模式


1. 概述

  有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

2. 解决的问题

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

3. 模式中的角色

  3.1 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

  3.2 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

  3.3 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

  3.4 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。

4. 模式解读

  4.1 观察者模式的类图  

  

  4.2 观察者模式的代码

复制代码
    /// <summary>
    /// 抽象主题类
    /// </summary>
    public abstract class Subject
    {
        private IList<Observer> observers = new List<Observer>();

        /// <summary>
        /// 增加观察者
        /// </summary>
        /// <param name="observer"></param>
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }

        /// <summary>
        /// 移除观察者
        /// </summary>
        /// <param name="observer"></param>
        public void Detach(Observer observer)
        {
            observers.Remove(observer);
        }

        /// <summary>
        /// 向观察者(们)发出通知
        /// </summary>
        public void Notify()
        {
            foreach (Observer o in observers)
            {
                o.Update();
            }
        }
    }

    /// <summary>
    /// 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
    /// </summary>
    public abstract class Observer
    {
        public abstract void Update();
    }

    /// <summary>
    /// 具体观察者或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
    /// </summary>
    public class ConcreteSubject : Subject
    {
        private string subjectState;

        /// <summary>
        /// 具体观察者的状态
        /// </summary>
        public string SubjectState
        {
            get { return subjectState; }
            set { subjectState = value; }
        }
    }

    /// <summary>
    /// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调
    /// </summary>
    public class ConcreteObserver : Observer
    {
        private string observerState;
        private string name;
        private ConcreteSubject subject;

        /// <summary>
        /// 具体观察者用一个具体主题来实现
        /// </summary>
        public ConcreteSubject Subject
        {
            get { return subject; }
            set { subject = value; }
        }

        public ConcreteObserver(ConcreteSubject subject, string name)
        {
            this.subject = subject;
            this.name = name;
        }

        /// <summary>
        /// 实现抽象观察者中的更新操作
        /// </summary>
        public override void Update()
        {
            observerState = subject.SubjectState;
            Console.WriteLine("The observer's state of {0} is {1}", name, observerState);
        }
    }
复制代码

  4.3 客户端代码

复制代码
    class Program
    {
        static void Main(string[] args)
        {
            // 具体主题角色通常用具体自来来实现
            ConcreteSubject subject = new ConcreteSubject();

            subject.Attach(new ConcreteObserver(subject, "Observer A"));
            subject.Attach(new ConcreteObserver(subject, "Observer B"));
            subject.Attach(new ConcreteObserver(subject, "Observer C"));

            subject.SubjectState = "Ready";
            subject.Notify();

            Console.Read();
        }
    }
复制代码

  运行结果

  

5. 模式总结

  5.1 优点

    5.1.1 观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。

  5.2 缺点

    5.2.1 依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。

  5.3 适用场景

    5.3.1 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。

    5.3.2 一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。

 

6. 模式引申,应用C#中的事件委托来彻底解除通知者和观察者之间的耦合。

   6.1 关于委托的定义:委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法有相同的行为。委托方法可以像其它任何方法一样,具有参数和返回值。委托可以看作是对函数(方法)的的抽象,是函数的“类”,委托的实例代表一个(或多个)具体的函数,它可以是多播的。

   6.2 关于事件:事件基于委托,为委托提供了一种发布/订阅机制。事件的订阅与取消与我们刚才讲的观察者模式中的订阅与取消类似,只是表现形式有所不同。在观察者模式中,订阅使用方法Attach()来进行;在事件的订阅中使用“+=”。类似地,取消订阅在观察者模式中用Dettach(),而事件的取消用“-=”。

 

7. 下面例子分别用观察者模式,事件机制来实现

  7.1 实例描述:客户支付了订单款项,这时财务需要开具发票,出纳需要记账,配送员需要配货。

  7.2 观察者模式的实现

    7.2.1 类图

    

    7.2.2 代码实现

复制代码
    /// <summary>
    /// 抽象观察者
    /// </summary>
    public interface ISubject
    {
        void Notify();
    }

    /// <summary>
    /// 工作岗位,作为这里的观察者的抽象
    /// </summary>
    public abstract class JobStation
    {
        public abstract void Update();
    }

    /// <summary>
    /// 具体主题,这里是客户
    /// </summary>
    public class Customer : ISubject
    {
        private string customerState;

        private IList<JobStation> observers = new List<JobStation>();

        /// <summary>
        /// 增加观察者
        /// </summary>
        /// <param name="observer"></param>
        public void Attach(JobStation observer)
        {
            this.observers.Add(observer);
        }

        /// <summary>
        /// 移除观察者
        /// </summary>
        /// <param name="observer"></param>
        public void Detach(JobStation observer)
        {
            this.observers.Remove(observer);
        }

        /// <summary>
        /// 客户状态
        /// </summary>
        public string CustomerState
        {
            get { return customerState; }
            set { customerState = value; }
        }

        public void Notify()
        {
            foreach (JobStation o in observers)
            {
                o.Update();
            }
        }
    }

    /// <summary>
    /// 会计
    /// </summary>
    public class Accountant : JobStation
    {
        private string accountantState;
        private Customer customer;

        public Accountant(Customer customer)
        {
            this.customer = customer;
        }

        /// <summary>
        /// 更新状态
        /// </summary>
        public override void Update()
        {
            if (customer.CustomerState == "已付款")
            {
                Console.WriteLine("我是会计,我来开具发票。");
                accountantState = "已开发票";
            }
        }
    }

    /// <summary>
    /// 出纳
    /// </summary>
    public class Cashier : JobStation
    {
        private string cashierState;
        private Customer customer;

        public Cashier(Customer customer)
        {
            this.customer = customer;
        }

        public override void Update()
        {
            if (customer.CustomerState == "已付款")
            {
                Console.WriteLine("我是出纳员,我给登记入账。");
                cashierState = "已入账";
            }
        }
    }

    /// <summary>
    /// 配送员
    /// </summary>
    public class Dilliveryman : JobStation
    {
        private string dillivierymanState;
        private Customer customer;

        public Dilliveryman(Customer customer)
        {
            this.customer = customer;
        }

        public override void Update()
        {
            if (customer.CustomerState == "已付款")
            {
                Console.WriteLine("我是配送员,我来发货。");
                dillivierymanState = "已发货";
            }
        }
    }
复制代码

    7.2.3 客户端代码

复制代码
    class Program
    {
        static void Main(string[] args)
        {

            Customer subject = new Customer();

            subject.Attach(new Accountant(subject));
            subject.Attach(new Cashier(subject));
            subject.Attach(new Dilliveryman(subject));

            subject.CustomerState = "已付款";
            subject.Notify();

            Console.Read();
        }
    }
复制代码

    运行结果:

    我是会计,我来开具发票。
    我是出纳员,我给登记入账。
    我是配送员,我来发货。

 

  7.3 事件实现

    7.3.1 类图

    

    通过类图来看,观察者和主题之间已经不存在任何依赖关系了。

    7.3.2 代码实现

    

复制代码
    /// <summary>
    /// 抽象主题
    /// </summary>
    public interface ISubject
    {
        void Notify();
    }

    /// <summary>
    /// 声明委托
    /// </summary>
    public delegate void CustomerEventHandler();

    /// <summary>
    /// 具体主题
    /// </summary>
    public class Customer : ISubject
    {
        private string customerState;

        // 声明一个委托事件,类型为 CustomerEventHandler
        public event CustomerEventHandler Update;

        public void Notify()
        {
            if (Update != null)
            {
                // 使用事件来通知给订阅者
                Update();
            }
        }

        public string CustomerState
        {
            get { return customerState; }
            set { customerState = value; }
        }
    }

    /// <summary>
    /// 财务,已经不需要实现抽象的观察者类,并且不用引用具体的主题
    /// </summary>
    public class Accountant
    {
        private string accountantState;

        public Accountant()
        { }

        /// <summary>
        /// 开发票
        /// </summary>
        public void GiveInvoice()
        {
            Console.WriteLine("我是会计,我来开具发票。");
            accountantState = "已开发票";
        }
    }

    /// <summary>
    /// 出纳,已经不需要实现抽象的观察者类,并且不用引用具体的主题
    /// </summary>
    public class Cashier
    {
        private string cashierState;

        public void Recoded()
        {
            Console.WriteLine("我是出纳员,我给登记入账。");
            cashierState = "已入账";
        }
    }

    /// <summary>
    /// 配送员,已经不需要实现抽象的观察者类,并且不用引用具体的主题
    /// </summary>
    public class Dilliveryman
    {
        private string dillivierymanState;

        public void Dilliver()
        {
            Console.WriteLine("我是配送员,我来发货。");
            dillivierymanState = "已发货";
        }
    }
复制代码

    7.3.3 客户端代码

复制代码
    class Program
    {
        static void Main(string[] args)
        {

            Customer subject = new Customer();

            Accountant accountant = new Accountant();
            Cashier cashier = new Cashier();
            Dilliveryman dilliveryman = new Dilliveryman();

            // 注册事件
            subject.Update += accountant.GiveInvoice;
            subject.Update += cashier.Recoded;
            subject.Update += dilliveryman.Dilliver;

            /*
             * 以上写法也可以用下面代码来替换
            subject.Update += new CustomerEventHandler(accountant.GiveInvoice);
            subject.Update += new CustomerEventHandler(cashier.Recoded);
            subject.Update += new CustomerEventHandler(dilliveryman.Dilliver);
             */

            subject.CustomerState = "已付款";
            subject.Notify();

            Console.Read();
        }
    }
复制代码

    运行结果

    我是会计,我来开具发票。
    我是出纳员,我给登记入账。
    我是配送员,我来发货。

修饰者模式

1、 装饰者模式,动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。

2、组合和继承的区别

继承。继承是给一个类添加行为的比较有效的途径。通过使用继承,可以使得子类在拥有自身方法的同时,还可以拥有父类的方法。但是使用继承是静态的,在编译的时候就已经决定了子类的行为,我们不便于控制增加行为的方式和时机。

组合。组合即将一个对象嵌入到另一个对象中,由另一个对象来决定是否引用该对象来扩展自己的行为。这是一种动态的方式,我们可以在应用程序中动态的控制。

与继承相比,组合关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。

3、装饰者模式的优缺点

优点

           1、装饰者模式可以提供比继承更多的灵活性

           2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。

           3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

           4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点

           1、会产生很多的小对象,增加了系统的复杂性

           2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

4、装饰者的使用场景

  1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。  当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

 以上内容来自网络

5、UML图(Astah/jude)下载地址:http://pan.baidu.com/s/1eQiVePc

6、示例:

装饰者基类

复制代码
 1 package com.xinye.test.decoration;
 2 /**
 3  * 食物基类
 4  * @author xinye
 5  *
 6  */
 7 public abstract class Food {
 8     
 9     protected String desc;
10     
11     public abstract String getDesc();
12 }
复制代码

鸡肉

复制代码
 1 package com.xinye.test.decoration;
 2 /**
 3  * 鸡肉
 4  * @author xinye
 5  *
 6  */
 7 public class Chicken extends Food {
 8     public Chicken(){
 9         desc = "鸡肉";
10     }
11     @Override
12     public String getDesc() {
13         return desc;
14     }
15 
16 }
复制代码

鸭肉

复制代码
 1 package com.xinye.test.decoration;
 2 /**
 3  * 鸭肉
 4  * @author xinye
 5  *
 6  */
 7 public class Duck extends Food {
 8     public Duck(){
 9         desc = "鸭肉";
10     }
11     @Override
12     public String getDesc() {
13         return desc;
14     }
15 
16 }
复制代码

装饰者基类

复制代码
 1 package com.xinye.test.decoration;
 2 /**
 3  * 
 4  * @author xinye
 5  *
 6  */
 7 public abstract class FoodDecoration extends Food {
 8 
 9     @Override
10     public abstract String getDesc();
11     
12 }
复制代码

蒸-装饰者

复制代码
 1 package com.xinye.test.decoration;
 2 /**
 3  * 蒸食物
 4  * @author xinye
 5  *
 6  */
 7 public class SteamedFood extends FoodDecoration {
 8     
 9     private Food food;
10     
11     public SteamedFood(Food f){
12         this.food = f;
13     }
14     
15     @Override
16     public String getDesc() {
17         return getDecoration() + food.getDesc();
18     }
19     
20     private String getDecoration(){
21         return "蒸";
22     }
23 }
复制代码

烤-装饰者

复制代码
 1 package com.xinye.test.decoration;
 2 /**
 3  * 烤食物
 4  * @author xinye
 5  *
 6  */
 7 public class RoastFood extends FoodDecoration {
 8     
 9     private Food food;
10     
11     public RoastFood(Food f){
12         this.food = f;
13     }
14     
15     @Override
16     public String getDesc() {
17         return getDecoration() + food.getDesc();
18     }
19     
20     private String getDecoration(){
21         return "烤";
22     }
23 }
复制代码

客户端

复制代码
 1 package com.xinye.test.decoration;
 2 /**
 3  * 客户端
 4  * @author xinye
 5  *
 6  */
 7 public class Client {
 8     public static void main(String[] args) {
 9         // 测试单纯的食物
10         Food f1 = new Chicken();
11         System.out.println(f1.getDesc());
12         
13         System.out.println("----------------------");
14         // 测试单重修饰的食物
15         RoastFood rf = new RoastFood(f1);
16         System.out.println(rf.getDesc());
17         
18         System.out.println("----------------------");
19         // 测试多重修饰的食物
20         SteamedFood sf = new SteamedFood(rf);
21         System.out.println(sf.getDesc());
22     }
23 }
复制代码

执行结果:
鸡肉
----------------------
烤鸡肉
----------------------
蒸烤鸡肉

 


单例模式


单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

代码1.0
public class SingletonClass{
    private static SingletonClass instance=null;
    public static SingletonClass getInstance(){
        if(instance==null){
            
                    instance=new SingletonClass();
                }
           
        
        return instance;
    }
    private SingletonClass(){}
}
但是这个没有解决同步的问题
代码2.0
public class SingletonClass{
    private volatile static SingletonClass instance=null;
    public static SingletonClass getInstance(){
        if(instance==null){
            synchronized(SingletonClass.class){
                if(instance==null){
                    instance=new SingletonClass();
                }
            }
        }
        return instance;
    }
    private SingletonClass(){}
}
注意变量的同步以及方法的同步


版权声明:本文为博主原创文章,未经博主允许不得转载。

Java设计模式 代码实例

  • 2017年12月09日 11:02
  • 388KB
  • 下载

c++设计模式百度云下载链接

  • 2017年12月08日 14:43
  • 320B
  • 下载

Tomcat 系统架构与设计模式,第 1 部分

本文以 Tomcat 5 为基础,也兼顾最新的 Tomcat 6 和 Tomcat 4。Tomcat 的基本设计思路和架构是具有一定连续性的。 Tomcat 总体结构 Tomcat 的结构很复杂,...

大话设计模式(带目录)

  • 2017年12月07日 10:45
  • 70.13MB
  • 下载

黑马程序员——Java学习之“浮”谈设计模式

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-开头首先推荐一下,也是我的老师老杨在授课时给我们强烈推荐的一本书,《Java与模式》,作者叫闫宏,此书中洋洋洒洒几...

软件设计模式

  • 2017年12月08日 15:24
  • 157KB
  • 下载

东北大学设计模式实验

  • 2017年12月07日 19:47
  • 85KB
  • 下载

设计模式学习笔记——开闭原则

定义: 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。 一、什么是开闭原则 举个书店售书的...

C++ 大话设计模式

  • 2017年12月01日 10:57
  • 85.24MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:设计模式
举报原因:
原因补充:

(最多只允许输入30个字)