Head First设计模式_注释笔记

设计原则

  1. 把可能变化之处独立出来,以免影响固定代码。
  2. 针对接口编程,而不是针对实现编程
  3. 多用组合,少用继承
  4. 设计交互对象之间的松耦合
  5. 扩展-关闭原则:类应该对扩展开发,对修改关闭。
  6. 依赖抽象,不要依赖具体类。
  7. 最少知识原则:只和你的密友谈话。
  8. 好莱坞原则:高层组件对待低层组件的方式:别调用我们,我们会调用你。
    避免高层和低层出现明显的环装依赖
  9. 一个类应该只有一个引起变化的原因。高内聚,低耦合。(单一职责)

备注

7:
//采用
public int GetCount()
{     return target.GetCount();     //只认识target        }
//不采用
public int GetCount()
{
     var obj=target.GetObj();     //多认识(依赖)了一个对象
     return obj.GetCount();
}

PS:如果某对象是调用其他方法的返回结果,不要调用它的方法。
意味着,不清楚他的方法细节。并不认识此对象,也就不依赖它。

针对接口(超类型)编程

针对实现:
Dog d=new Dog();
d.bark();
针对接口:
Animal a=new Dog();
a.makeSound();
运行时
Animal a=getAnimal();
a.makeSound();

策略模式

定义

定义了算法族,分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。

类图

类图

观察者模式

定义

定义了对象间的一对多依赖(订阅),这样依赖,当一个对象改变时,它的所有依赖者都会受到通知并更新。Subject主题,Observer观察者。

类图

类图

代码示例

PS:另可以用多播委托实现此过程。

public class DeleteAction : IDisposable
{
    private readonly Action _onDispose;
    public DeleteAction(Action onDispose)
    {            _onDispose = onDispose;        }

    public void Dispose()
    {            _onDispose();        }
}
public class Msg
{        public string Name { get; set; }    }

public class Report : IObservable<Msg>
{
    private List<IObserver<Msg>> os = new List<IObserver<Msg>>();

    public void Notify(string msg)
    {os.ForEach(o => { o.OnNext(new Msg { Name = msg }); o.OnCompleted(); });}

    public IDisposable Subscribe(IObserver<Msg> observer)
    {
        os.Add(observer);
        return new DeleteAction(() => { os.Remove(observer); });
    }

    public void Err()
    {os.ForEach(o => { o.OnError(new Exception("自定义错误!")); });}
}
public class Screen : IObserver<Msg>
{
    public int Id { get; set; }
    public Screen(int id)        {            Id = id;        }
    public void OnNext(Msg value)
    {Console.WriteLine("接收Id:" + Id + ",信息为:" + value.Name);}

    public void OnError(Exception error)
    {Console.WriteLine("接收Id:" + Id + ",错误!信息:" + error.Message);}

    public void OnCompleted()
    {Console.WriteLine("接收Id:" + Id + ",完成!");}
}
class Program
{
    static void Main(string[] args)
    {
        Report re = new Report();
        Screen s1 = new Screen(1);
        Screen s2 = new Screen(2);
        var o1 = re.Subscribe(s1);
        var o2 = re.Subscribe(s2);
        re.Notify("哎呀");
        o1.Dispose();
        re.Notify("少人");
    }
}

装饰者模式

定义

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

类图

类图

代码示例

public abstract class Phone
{
    public abstract void Ring();
    public abstract decimal GetPrice();
}
public class Apple : Phone     //被装饰者
{
    public override void Ring()        
    {    Console.WriteLine("这是苹果手机...");        }
    public override decimal GetPrice()        
    {            return 4500;        }
}
public abstract class Decorator : Phone     //装饰者
{
    protected Phone p;     //被装饰者引用
    protected Decorator(Phone p)        
    {            this.p = p;        }
}
public class Sticker : Decorator 
{
    public Sticker(Phone p)   : base(p)        {        }
    public override void Ring()
    {
        p.Ring();    //被装饰者行为
        AddSticker();     //新增行为/责任
    }
    public override decimal GetPrice()        
    {return p.GetPrice() + 1.5m;}
    public void AddSticker()        
    {Console.WriteLine("加了贴膜!");}
}
    static void Main(string[] args)
    {
        Phone m = new Apple();
        m = new Sticker(m);
        m = new Sticker(m);    //贴了2层
        m = new Accessories(m);

        m.Ring();
        Console.WriteLine("当前价格为:" + m.GetPrice());
        Console.ReadKey();
    }

角色

抽象构件(Phone)角色:给出一个抽象接口,以规范准备接受附加责任的对象。
具体构件(AppPhone)角色:定义一个将要接收附加责任的类。
装饰(Dicorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
具体装饰(Sticker和Accessories)角色:负责给构件对象 ”贴上“附加的责任。

理解

优点:
装饰者模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
装饰者模式有很好地可扩展性
缺点:
装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

适配器模式

定义

将一个类的接口,转换成客户(使用者)期望的另一个接口。适配器让原本不兼容的类可以合作无间。

类图

类图

代码示例

public interface IDuck    {        void Quack();    }
public interface ITurkey    {        void SpecialQuack();    }
public class Duck : IDuck     //鸭子类
{
    public void Quack()        
    {            Console.WriteLine("鸭子叫!");        }
}
public class Turkey : ITurkey     //火鸡类
{
    public void SpecialQuack()        
    {      Console.WriteLine("火鸡叫!");        }
}
public class Adapter : IDuck     //适配器,把火鸡转换成鸭子
{
    private ITurkey t;     //持有(包装)的火鸡引用
    public Adapter(ITurkey t)        
    {            this.t = t;        }
    public void Quack()
    {            t.SpecialQuack();        }
}
class Program
{
    static void Main(string[] args)
    {
        Adapter duckAdapter = new Adapter(new Turkey());   //使用适配器切换了接口
        ShootDuck(duckAdapter);     //原调用代码,不用更改。
        Console.ReadKey();
    }
    static void ShootDuck(IDuck d)        
    {            d.Quack();        }     //原调用代码,不用更改。
}

理解

系统A,原本某一块功能(如客户出入金)需要从一个提供商甲切换到提供商乙,不改变系统代码的情况下。可以创建适配器,封装乙的接口实现切换动作,让系统仍然像使用甲的接口那样,正常运作。过程不需修改代码,只需扩展适配器。处理遗留问题。

装饰者和适配器的异同

适用条件的差别:
装饰模式一般在下列情况使用:需要扩展一个类的功能或者给你个类增加附加责任;需要动态的给一个对象增加功能,这些功能可以再动态的撤销;需要增加有一些基本功能的排列组合而产生非常大量的功能,从而使得继承关系变得不现实。
适配器模式一般使用的情况包括:系统需要使用现有的类,但此类已经不符合系统的需要;
想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的的类一起工作。适配器模式在系统升级的时候使用的频率很高,对旧系统的一些功能方法在新系统中引用。

单例模式

定义

确保一个类只有一个实例,并提供一个全局访问点。

代码示例

线程安全

public class Singleton
{
    private Singleton() { }
    private static Singleton singleton;
    public static Singleton GetInstance()
    {
        if (singleton == null)
        {
            lock (typeof(Singleton))
            {
                if (singleton == null)
                {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

命令模式

定义

将“请求”封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销的操作。

类图

类图

代码示例

public class Receiver
{
    public void Action()
    {            Console.WriteLine("Called Receiver.Action()");        }
}
public abstract class Command
{
    protected Receiver receiver;
    public Command(Receiver receiver)
    {        this.receiver = receiver;        }
    public abstract void Execute();
}
public class ConcreteCommand : Command
{
    public ConcreteCommand(Receiver receiver): base(receiver){}
    public override void Execute()        
    {            receiver.Action();        }
}
public class Invoker
{
    private Command _command;
    public void SetCommand(Command command)
    {            this._command = command;        }
    public void ExecuteCommand()
    {            _command.Execute();        }
}
    static void Main(string[] args)
    {
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(receiver);
        Invoker invoker = new Invoker();
        invoker.SetCommand(command);
        invoker.ExecuteCommand();
    }

理解

将请求者和执行者(接受者)解耦。
如果执行者种类繁多,且不属于同一个体系,也没有统一执行接口。请求者请求命令,需要知道所有执行者的外露接口,耦合很高。
命令模式,加入中间层:调用者,让请求者只认识调用者,向调用者发出指定执行者且接口固定的命令对象,调用者只执行指定命令对象的固定接口,命令对象包含执行者的引用和一组方法,知道如何完成操作。
这种封装命令对象的模式,为命令模式。如待完成列表,可以在任何时间被执行。

外观模式

定义

提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易适用。

类图

类图

代理模式

定义

为另一个对象提供一个替身或占位符以控制对这个对象的访问。

类图

类图

类图

代理分类

  • 远程代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。这样可以隐藏一个对象在不同地址空间的事实。
    例如:WebService,WCF
  • 虚拟代理: 根据需要创建一个资源消耗较大的对象,通过它来存放实例化需要长时间的真实对象,使得此对象只在需要时才会被真正创建。
  • 保护代理:用来控制真实对象的访问时的权限。如果需要,可以给不同的用户提供不同级别的使用权限。
  • 智能代理:指当调用真实对象时,代理处理另外一些事。提供一些额外的操作,比如将对此对象调用的次数记录下来等。
  • 同步(Synchronization)代理:多线程情况下,为主题提供安全的访问。
  • 复杂隐藏(Complexity Hiding)代理:隐藏一个类的复杂集合的复杂度,有时候称为外观代理(Facade Proxy)。此代理控制访问,外观模式只提供另一组接口。
  • 写入时复制(Copy-on-Write)代理:虚拟代理的变种。把复制(克隆)延迟到只有在客户端需要时,才真正采取行动。
  • 缓存(Cache)代理:为开销大的运算结果提供临时的存储空间,以便多个客户端可以共享这些结果,以减少计算或网络延迟。
  • 防火墙(Firewall)代理:控制网络资源的访问,不让恶意用户接近。

装饰者,外观,代理,适配器四种模式的比较

类图

工厂方法模式

定义

定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

类图

类图

抽象工厂模式

定义

提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指明具体类。

类图

类图

模板方法模式

定义

在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

类图

类图

代码示例

public abstract class Beverage
{
    public void Prepare()
    {
        BoilWater();
        Brew();
        PourInCup();
        //钩子,可由子类视情况(是否覆盖),反控制基类中的算法(顺序或步骤)
        if (IsCondiments())     
        {                AddCondiments();            }
    }
    protected abstract void AddCondiments();     //由子类实现部分算法
    protected abstract void Brew();     //可有子类控制,推迟到子类中实现
    protected virtual bool IsCondiments()     
    {      return false;   }     //钩子

    private void PourInCup()        
    {       Console.WriteLine("倒入杯子");     }     //基类默认实现部分

    private void BoilWater()        
    {       Console.WriteLine("烧水");        }     //同上
}
public class Coffee : Beverage
{
    protected override bool IsCondiments()        
    {            return GetResult();        }     //根据结果是否覆盖使用此钩子

    protected override void AddCondiments()
    {            Console.WriteLine("加糖,加奶");        }

    protected override void Brew()
    {            Console.WriteLine("磨碎咖啡豆,泡咖啡粉...");        }
}
    static void Main(string[] args)
    {
        Beverage co = new Coffee();
        co.Prepare();
    }

模板方法模式的变种

不使用继承,而使用组合。
java中Arrays.sort(object[] arr)中的算法,进行两个对象之间的比较。

...
 Comparable obj...     //接口
 obj.compareTo(obj2)...
...

算法待实现部分,不再交由子类负责实现(数组不可继承)。而是传入一个实现了Comparable接口的元素组成的数组,由此数组的元素负责。

模板方法模式和工厂方法模式,区别

模板方法,指的是实现算法的方法,包含基类实现部分和待子类实现部分(抽象方法)。
工厂方法,指的是可由子类继承实现的抽象方法,不同子类决定不同的功能。会由基类调用。

迭代器模式

定义

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

类图

类图

代码示例

public class Item
{
    public string Name { get; set; }
    public double Price { get; set; }

    public override string ToString()
    {            return "名称:" + Name + ",价格:" + rice;        }
}
public class MenuManager : IEnumerable     //可被foreach迭代
{
    private Item[] items;
    private int Index { get; set; }
    public MenuManager()
    {
        items = new Item[10];
        AddItem("煎饼", 2);
        AddItem("拉面", 7);
        AddItem("快餐", 10);
    }
    public IEnumerator GetEnumerator()
    { return new MenuEnumrator(items); }  //继承实现,返回一个迭代器供foreach使用
    public void AddItem(string name, double price)
    {
        Item i = new Item { Name = name, Price = price };
        items[Index] = i;
        Index++;
    }
    public void ChgItem(string name, double price, int destIndex)
    {
        Item i = new Item { Name = name, Price = price };
        items[destIndex] = i;
    }
}
public class MenuEnumrator : IEnumerator     //迭代器接口
{
    private List<Item> list;
    private int index;
    public MenuEnumrator(IEnumerable<Item> arr)
    {
        list = arr.ToList();
        index = -1;
    }
    public bool MoveNext()     //继承实现,先后移动
    {
        index++;
        bool result = list.Count > index && list[index].Price < 3;     //自定义条件
        if (result)
            Current = list[index];
        return result;
    }
    public void Reset()
    {            index = -1;        }     //继承实现,重置索引
    public object Current { get; private set; }     //继承实现,当前项
}
class Program
{
    static void Main(string[] args)
    {
        MenuManager dm = new MenuManager();
        dm.AddItem("汽水", 1);
        foreach (Item item in dm)
        {
            Console.WriteLine(item);
        }
        dm.ChgItem("干拌面", 9, 1);
    }
}

组合模式

定义

允许你将对象组合成树形结构来表现“整体/部分”层次结构。
组合能让客户以一致的方式处理个别对象以及对象组合。

安全式和透明式组合模式:
透明式:
以单一责任设计原则换取透明性。减少客户代码,失去了一些安全性。可能会抛出异常。
安全式:
将责任区分开放在不同的接口中,符合单一责任原则。比较安全,但失去了透明性。客户代码必须判断类型,处理不同类型的节点。

类图

类图

透明式的组合模式

public class Graphics
{
    protected string Name { get; set; }
    protected Graphics(string name)        {            this.Name = name;        }
    public virtual void Draw()
    {            throw new NotSupportedException();        }

    //默认抛出异常,避免叶对象或不合理的操作。
    //简单图形(叶对象)Add或Remove方法没有任何意义
    //如果客户端调用了将会抛出异常
    public virtual void Add(Graphics g)
    {            throw new NotSupportedException();        }
    public virtual void Remove(Graphics g)
    {            throw new NotSupportedException();        }
}

public class Line : Graphics
{
    public Line(string name) : base(name) { }
    public override void Draw()
    {            Console.WriteLine("画 " + Name);        }
}

public class Circle : Graphics
{
    public Circle(string name) : base(name) { }
    public override void Draw()
    {            Console.WriteLine("画 " + Name);        }
}

public class ComplexGraphics : Graphics
{
    public ComplexGraphics(string name) : base(name) { }
    private List<Graphics> list = new List<Graphics>();
    public override void Draw()
    {
        foreach (var item in list)
            item.Draw();
    }

    public override void Add(Graphics g)
    {            list.Add(g);        }
    public override void Remove(Graphics g)
    {            list.Remove(g);        }
}

class Program
{
    static void Main(string[] args)
    {
        Graphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
        complexGraphics.Add(new Line("线段A"));
        Graphics l = new Line("线段B");
        complexGraphics.Add(l);
        Graphics CompositeCG = new ComplexGraphics("一个圆和一条线组成的复杂图形");
        CompositeCG.Add(new Circle("圆"));
        CompositeCG.Add(new Circle("线段C"));
        complexGraphics.Add(CompositeCG);

        // 显示复杂图形的画法
        Console.WriteLine("复杂图形的绘制如下:");
        complexGraphics.Draw();
        Console.WriteLine("复杂图形绘制完成\n");

        // 移除一个组件再显示复杂图形的画法
        complexGraphics.Remove(l);
        Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
        complexGraphics.Draw();
        Console.WriteLine("复杂图形绘制完成");
    }

}

安全式的组合模式

public abstract class Graphics
{
    protected string Name { get; set; }
    protected Graphics(string name)
    {            this.Name = name;       }
    public abstract void Draw();
    // 移除了Add和Remove方法
    // 把管理子对象的方法放到了ComplexGraphics类中进行管理
    // 因为这些方法只在复杂图形中才有意义,且符合单一责任原则。
}

public class Line : Graphics
{
    public Line(string name) : base(name) { }
    public override void Draw()
    {            Console.WriteLine("画 " + Name);        }
}
public class Circle : Graphics
{
    public Circle(string name) : base(name) { }
    public override void Draw()
    {            Console.WriteLine("画 " + Name);        }
}
public class ComplexGraphics : Graphics
{
    public ComplexGraphics(string name) : base(name) { }
    private List<Graphics> list = new List<Graphics>();
    public override void Draw()
    {
        foreach (var item in list)
            item.Draw();
    }
    public void Add(Graphics g)
    {            list.Add(g);        }
    public void Remove(Graphics g)
    {            list.Remove(g);        }
}
class Program
{
    static void Main(string[] args)
    {
        ComplexGraphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
        complexGraphics.Add(new Line("线段A"));
        Line l = new Line("线段B");
        complexGraphics.Add(l);
        ComplexGraphics CompositeCG = new ComplexGraphics("一个圆和一条线组成的复杂图形");
        CompositeCG.Add(new Circle("圆"));
        CompositeCG.Add(new Circle("线段C"));
        complexGraphics.Add(CompositeCG);

        // 显示复杂图形的画法
        Console.WriteLine("复杂图形的绘制如下:");
        complexGraphics.Draw();
        Console.WriteLine("复杂图形绘制完成");

        // 移除一个组件再显示复杂图形的画法
        complexGraphics.Remove(l);
        Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
        complexGraphics.Draw();
        Console.WriteLine("复杂图形绘制完成");
    }
}

状态模式

定义

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

类图

类图

代码示例

Machine:

public class Machine
{
    internal State SoldOutState { get; set; }        //内部包装的状态
    internal State NoCoinState { get; set; }
    internal State HasCoinState { get; set; }
    internal State SoldingState { get; set; }
    public int Count { get; internal set; }    //对外暴露的显示
    public int CoinCount { get; internal set; }
    internal State State { get; set; }
    public Machine(int count)
    {
        SoldOutState = new SoldOutState(this);
        NoCoinState = new NoCoinState(this);
        HasCoinState = new HasCoinState(this);
        SoldingState = new SoldingState(this);
        Count = count;
        CoinCount = 0;
        State = count > 0 ? NoCoinState : SoldOutState;
    }
    public void Insert() { State.Insert(); }
    public void Eject() { State.Eject(); }
    public void Turn()    //对外暴露的接口(按钮)
    {
        State.Turn();    //内部执行的动作,由状态类负责
        if (CoinCount > 0)
            State.Give();
    }
    internal void SetState(State state) { State = state; }
    public void FillBall(int count)
    {
        Console.WriteLine("上货" + count + "个");
        Count += count;
    }
    internal void ReleaseBall()
    {
        Console.WriteLine("发放商品");
        if (Count != 0)
            Count--;
    }
    public override string ToString()
    {
        return "\n============================\n自动售货机\n货物个数:" + Count + "\t当前状态:" + State + "\n============================\n";
    }
}

状态类:

internal abstract class State
{
    public abstract void Insert();
    public abstract void Eject();
    public abstract void Turn();
    public abstract void Give();
    protected virtual void Error() { Console.WriteLine("错误操作"); }
}

internal class NoCoinState : State
{
    private Machine Mac { get; set; }
    public NoCoinState(Machine mac) { Mac = mac; }
    public override void Insert()
    {
        Console.WriteLine("投入硬币");
        Mac.CoinCount++;
        Mac.SetState(Mac.HasCoinState);
    }
    public override void Eject() { Error(); }
    public override void Turn() { Error(); }
    public override void Give() { Error(); }
    public override string ToString() { return "等待投入硬币..."; }
}

internal class HasCoinState : State
{
    private Machine Mac { get; set; }
    public HasCoinState(Machine mac){Mac = mac;}
    public override void Insert(){Error();}
    public override void Eject()
    {
        Console.WriteLine("硬币归还");
        Mac.CoinCount--;
        Mac.SetState(Mac.NoCoinState);
    }
    public override void Turn()
    {
        Console.WriteLine("转动");
        Mac.SetState(Mac.SoldingState);
    }
    public override void Give(){Error();}
    public override string ToString(){return "有硬币,可以转动...";}
}

internal class SoldingState : State
{
    private Machine Mac { get; set; }
    public SoldingState(Machine mac) { Mac = mac; }
    public override void Insert() { Error(); }
    public override void Eject() { Error(); }
    public override void Turn() { Error(); }
    public override void Give()
    {
        Mac.ReleaseBall();
        if (Mac.Count > 0)
            Mac.SetState(Mac.NoCoinState);
        else
        {
            Console.WriteLine("已售罄");
            Mac.SetState(Mac.SoldOutState);
        }
    }
    public override string ToString() { return "正在出货..."; }
}

internal class SoldOutState : State
{
    private Machine Mac { get; set; }
    public SoldOutState(Machine mac) { Mac = mac; }
    public override void Insert() { Error(); }
    public override void Eject() { Error(); }
    public override void Turn() { Error(); }
    public override void Give() { Error(); }
    public override string ToString() { return "已售罄..."; }

}

测试代码:

class Program
{
    static void Main(string[] args)
    {
        Machine mac = new Machine(5);
        Console.WriteLine(mac);
        mac.Eject();
        mac.Turn();
        mac.FillBall(1);
        mac.Insert();
        Console.WriteLine(mac);
        mac.Eject();
        mac.Insert();
        mac.Insert();
        mac.Turn();
        mac.Turn();

        Console.ReadKey();
    }

}

模式配对

类图

模式分类

类图

欢迎打赏