备注:由于读的电子书版本是pdf的,影印都有些看不清楚。所有练习代码都单独放到了GitHub上方便以后查看。
https://github.com/yuhezhangyanru/DesignPatternDemoCollection

注:本书主要是针对Java讲的,涉及到语法特性的时候,每种语言特性不尽相同,不能一概而论–作者 秦晓波

首先必须说明看这本书的过程中越看越觉得棒!第一遍看的时候还不怎么懂,尤其你如果常用语言非Java的话,光看更没有什么用,最好是遇到的例子用自己习惯的语言再实现一边,会发现书中阐述的道理真的非常实用!

六大设计原则:

- (1)单一职责原则(SingleResposibilityPrinciple),简称SRP。

要求一个类或接口只有一个原因引起变化,也就是只负责一件事情。
单一职责的好处:
降低类的复杂性,定义清晰明确;
提高可读性;
提高可维护性;
降低修改引起的风险;
但是具体怎么划分职责还需要具体项目实际考虑。
单一职责适用于接口、类,同时也可以用在方法中,一个方法尽可能只做一件事情。类的设计方法尽量做到只有一个原因引起变化。

- (2)里式替换原则。LiskovSubstitution Principle,简称 LSP。为了实现更好的继承方式。

简单定义:所有引用基类的地方必须能透明的使用其子类的对象。
换句话说,只要父类出现的地方,就可以出现子类,而且替换成子类也不会产生任何异常的。使用者并不知道用的父类还是子类,但反过来就不行了,使用子类的时候,父类未未必适应。因为子类的成员和方法可能多余父类。
该原则定义的规范:
1,子类必须完全实现父类方法:设计系统用到一个接口或抽象类的时候,一般在调用类中直接传入接口或父类对象而非子类,调用的人不需要关心具体调用的是什么类型的子类

public class Father
{public virtual void testFunc(Father obj)//此处传入的类型尽量为Father类型,外部调用{}
}public class Child2:Father
{
}public class Child:Father
{ //此处传入的类型尽量为Father类型,外部调用时不用关心具体是Child还是Child2类型的public override void testFunc(Father obj){}
}

2,子类可以有自己的个性,但注意的是向下转型不安全,即子类强转为父类的时候。所以子类出现的地方未必可以出现父类
3,覆盖或实现父类方法时输入参数可以被放大..呵呵,这条原则建议慎用额!
C#和Java的继承还是有差别的 TODO page15中的例子,用C#和java重新实现一遍,看看书里面说的是不是对的!

- (3) 依赖倒置原则,Dependence Inversion Principle,DIP

具体含义:
1. 高层模块不应该依赖低层模块,两者都应该依赖其抽象
2. 抽象不应该依赖细节
3. 细节应该依赖抽象
注:不可分割的原子模块就是低层模块,原子逻辑再组装就是高层模块。在Java中,抽象指接口或抽象类,不能被直接实例化的,细节就是实现类(子类)。依赖倒置在Java中的表现,我就不说实现抽象之类的了,头疼,直接简单描述为子类父类了:
1. 模块间通过依抽象来产生依赖,子类不直接产生依赖,其依赖关系通过接口或父类产生;
2. 接口或父类不依赖与子类;
3. 子类依赖接口或父类;
这也是面向接口编程的思想(Object Oriented-Design OOD)之一
本质:
- 通过抽象(接口或)

- (4) 接口隔离原则

首先看定义,java中接口的含义分为以下两种:
- 实例接口,属于抽象类,类似于C++中的父类;
- 类接口,通过interface关键字定义的接口;
“隔离”的含义:
- 客户端不依赖不需要的接口,即避免冗余的依赖;
- 类间的依赖关系应建立在最小接口上,要求接口的功能细化;

简单来说,设计简单的接口,避免臃肿庞大的接口;

page30接口和抽象类使用例子:见笔记:C#接口和抽象类使用

- (5) 迪米特法则

(Low of Demeter, LoD)又称最少知识原则,通俗说尽量减少类之间的耦合度,
减少类的public方法
如果一个方法放在本类中,既不增加类间关系,也对本类没有负面影响,那就放置在本类中

- (6) 开闭原则

类、模块和函数应该对扩展开放,对修改关闭。通俗讲是尽量通过扩展已有的行为来实现变化而非直接修改已有代码

具体设计模式的学习和案例

单例模式:

1.单例模式:

需求及使用场景:
- 项目中要求只有一个对象时
- 创建对象消耗太多或频繁创建销毁
- 或包含大量静态常量/静态方法

++确保只有一个实例++

优点:
- 减少内存开支
- 避免对资源的多重占用
- 可以在系统设置全局的访问点
- 优化和共享资源访问
缺点:
- 一般没有接口,扩展困难
- 与单一职责原则有冲突

using System;
//单例模式的例子:只允许外部获取一个实例对象
public class Emperor
{private static Emperor emperor = new Emperor();  //把构造函数指定为私有的,外部就不能实例化了private Emperor() {}public static Emperor getInstance(){return emperor;}public void say(){System.Console.WriteLine("我是皇帝");}
}public class Client
{public static void Main(string[] args){Emperor emperor= Emperor.getInstance();emperor.say();}

上面的例子是正常的,但是下面的例子在高并发的时候会存在线程不安全,可能产生多个实例:

public static Singleton getInstance()
{if(singleton==null){singleton =new Singleton();}return singleton;
}

TODO 详细的线程安全见7-3的例子


工厂方法模式

需要注意的是:在接口方法的声明中,书中以Java为例的接口成员都指明了public类型,但不是所有语言都能指定public,如C#就不需要指定已经强制为public,直接声明成员即可。

定义:

定义一个用户创建对象的接口,让子类决定要实例化哪个类,适用于需要灵活/可扩展的框架

优缺点:

优点:
- 良好封装性,不用关系具体类是如何实例化的
- 创建对象有条件约束,如知道类名或基类型
- 可扩展性强,增加子类型不需要修改工厂

demo举例:

//抽象工厂接口类public abstract class AbstractHumanFactory{public abstract T createHuman<T>();}//具体生产Human类型的工厂子类public class HumanFactory : AbstractHumanFactory{public override T createHuman<T>( ){Human human = null;try{human = (Human)Activator.CreateInstance(typeof(T));}catch (Exception e){Console.WriteLine("excep=" + e.ToString());}return (T)human;}}
//具体Human基类型:声明为interface
  public interface Human{void getColor();void talk();}//子类实现举例public class WhiteHuman : Human{public void getColor(){Console.WriteLine("白色人种 皮肤白色");}public void talk(){Console.WriteLine("白色人种 说单字节");}}

最后补充测试demo:

 private static void CreateHumanTest(){AbstractHumanFactory yinyanglu = new HumanFactory();Human whiteHuman = yinyanglu.createHuman<WhiteHuman>();whiteHuman.getColor();whiteHuman.talk();Human blackHuman = yinyanglu.createHuman<BlackHuman>();blackHuman.getColor();blackHuman.talk();Human yellowHuman = yinyanglu.createHuman<YellowHuman>();yellowHuman.getColor();yellowHuman.talk();//注意:yinyanglu已经限制为人Human及子类型,TestDeleteClass普通类实例化会报错//yinyanglu.createHuman<TestDeleteClass>();}
注意:以上的demo可以作为在C#中的工厂框架来使用,但是原书中的Product抽象工厂demo,我尝试了在C#中是不行的,也就是说在C#中抽象接口类实例化的基可类型得是接口interface(即Human是interface),否则如果Human是抽象类例如如下声明的话:
  public abstract class Human{public void method1(){}public abstract void method2();}

在抽象工厂HumanFactory方法中实例化完毕要返回时转换数据类型编译不过,即return (T)human这一步无法通过,如果想混顺利执行的话,工厂返回的对象类型就不能使泛型了必须指明实例化类型是父类Human。

  public class HumanFactory : AbstractHumanFactory{public override Human createHuman<Human>(){Human human1 = default(Human);try{human1 = (Human)Activator.CreateInstance(typeof(Human));}catch (Exception e){Console.WriteLine("excep=" + e.ToString());}return human1;}}

为了全面对照,由于我不熟悉Java的抽象类和接口有什么区别,按照定义就查了一下,
这个作者的分享写的非常好,赞一个
其实在C#里大部分也是如此:

抽象类:
- Java中的抽象类就是“包含”抽象方法的类(成员为public或protected),“包含”二字很重要,未必一定有抽象方法,也未必方法都是抽象方法,抽象方法只能声明不能实现,但普通方法可以实现;
- 不能直接用来实例化,是为了让子类继承;
- 继承了抽象类的子类必须实现(即覆写)所有抽象方法;
- 子类只能继承一个抽象类,目前我知道只有C++支持多继承,C#多继承也是编译不过的;

接口类:
- 所有成员都是public(C#中直接声明定义,不能指定修饰符);
- 所有“成员”都是抽象方法;
- 不能包含静态方法;
- 子类可以实现多个接口;

工厂方法的扩展:

简单工厂模式:

demo:

    public class HumanFactorySimple{//不用实例工厂,直接用staticpublic static T createHuman<T>(){Human human = null;try{human = (Human)Activator.CreateInstance<T>();}catch (Exception e){Console.WriteLine("e=" + e.ToString());}return (T)human;}}
多个工厂模式:

属于复杂工厂模式,简单来说就是一个实例化类对应一个构造工厂
多工厂的基类:

   public abstract class AbstractHumanFact1{public abstract Human createHuman();}

子工厂实现:

  public class HumanYellowFactory : AbstractHumanFact1{public override Human createHuman(){return new YellowHuman();}}

实例化对象的使用:

   Human yellow1 = (new HumanYellowFactory()).createHuman();yellow1.talk();
替代单例模式:

专门定义一个工厂来来创建单例,但是在C#中实现可能会“啰嗦”一点,这个工厂创建单例的基本思路是类的声明构造指定为private即外部无法直接new一个出来,然后定义一个工厂反射获得类的默认构造来实例化一个,当然“实例化”的动作又放在工厂自己的静态构造里,保障不被多次执行。这么啰嗦,以下是这个工厂的实现demo。

关于C#访问默认构造,我借鉴的这篇文章

被实例化的单例类:

public class Singleton
{private Singleton(){}public void doSomeThing(){Console.WriteLine("doSomeThing 测试方法执行");}
}

工厂类:

using System;
using System.Reflection;public class SingletonFactory
{private static Singleton singleton;static SingletonFactory(){try{Type type = typeof(Singleton);System.Reflection.ConstructorInfo[] constructorInfoArray = type.GetConstructors(System.Reflection.BindingFlags.Instance| System.Reflection.BindingFlags.NonPublic| System.Reflection.BindingFlags.Public);System.Reflection.ConstructorInfo noParameterConstructorInfo = null;foreach (System.Reflection.ConstructorInfo constructorInfo in constructorInfoArray){System.Reflection.ParameterInfo[] parameterInfoArray = constructorInfo.GetParameters();if (0 == parameterInfoArray.Length){noParameterConstructorInfo = constructorInfo;break;}}if (null == noParameterConstructorInfo){throw new NotSupportedException("No constructor without 0 parameter");}singleton = (Singleton)noParameterConstructorInfo.Invoke(null);}catch (Exception e){Console.WriteLine("e=" + e.ToString());}}public static Singleton getSingleton(){return singleton;}
}

最后要想取用单例的话直接访问SingletonFactory.getSingleton()就可以了。

延迟初始化,或者说用来缓存多个对象

如下demo,ConcreteProduct1和ConcreteProduct2都继承自Product,其中如下ConcreteProduct2可以得知当前有几个对象来测试

public class ConcreteProduct2 : Product
{static int index = 0;public ConcreteProduct2(){index++;}public override void method2(){Console.WriteLine("ConcreteProduct2 的method2 index=" + index);}
}

用来缓存的工厂类:

public class ProductFactoryDelay
{private static Dictionary<string, Product> prMap = new Dictionary<string, Product>();public static Product createProduct(string type){Product product = null;if (prMap.ContainsKey(type)){product = prMap[type];}else{if (type.Equals("ConcreteProduct1")){product = new ConcreteProduct1();}else{product = new ConcreteProduct2();}prMap.Add(type, product);}return product;}
}

测试使用:

  private static void FactoryCacheTest(){Product p1 = ProductFactoryDelay.createProduct(typeof(ConcreteProduct1).Name);Product p2 = ProductFactoryDelay.createProduct(typeof(ConcreteProduct2).Name);p1.method2();p2.method2();Product p3 = ProductFactoryDelay.createProduct(typeof(ConcreteProduct2).Name);p3.method2();} 

最后根据打印结果发现 p2.method2()和 p3.method2()执行相同的内容,说明p2,p3取的是同一个对象,在某些场景重要保证实例对象的时候这个方法比较实用

抽象工厂模式(Abstract Factory Pattern)

定义:为创建一组相关/或相互依赖的对象提供一个接口,而无需指定它们的具体类。抽象工厂是工厂方法的升级版,

而抽象工厂类用来定义/声明每个子工厂的功能

简单说就是给有共同特性的几个工厂类加一个父类!

优点:
  • 封装性,工厂基类只需关心抽象和接口,不用关心工厂具体的实现;

- 产品实现类的约束非公开,即高层工厂不需要知道具体工厂内的

使用场景:

- 一组具有相同约束的对象,例如文本编辑器,在不同的操作系统里虽然显示和使用相同,但实现上不相同,可以通过抽象工厂来实现各个操作系统下的文本编辑器

模板方法模式

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

注意:抽象模板里的基本方法尽量用protected类型, 不需要暴露的部分privte。实现类非必要的话, 尽量不要扩大父类的访问权限。

优缺点:

优点:
- 封装不变部分,扩展可变部分:不变的算法部分放到父类
- 提取部分公共代码,便于维护
- 行为由父类控制,子类实现
缺点:
子类实现的执行结果影响父类的结果,(继承???),在复杂项目中

使用场景:

1.多个子类有公有方法,并且逻辑基本相同时
2.重要、复杂算法时 可以把核心算法设计为模板方法,细节由子类来实现
3.重构的生活,把相同代码提取到父类,通过钩子函数约束子类行为。

什么是钩子函数(Hook Method)?
比如抽象类中一个函数的返回值会影响到模板方法的执行结果(preturn true or false 有不同的响应),这个方法就叫钩子方法。

建造者模式(Builder Pattern)

定义:建造者模式也叫生成器模式,即将一个复杂对象的构建和它的表示分离开,使得同样的建造过程可以创建不同的表示。

建造者模式中的四个角色:

Product产品类:通常是实现了模板方法模式,也就是有模板方法和基本方法
Builder抽象建造者:规范产品组建,一般由子类实现
ConcreteBuilder具体建造者:实现抽象类定义的所有方法,并且返回一个组件好的对象,有几个产品类就有几个具体建造者
Director导演类:负责安排已有模块的顺序,告诉抽象建造者去建造产品

模式应用:

优缺点:

1.封装性:客户端不必知道产品内部细节,不用关心模型内部具体实现
2.建造者相互独立,荣誉扩展
3.便于控制细节风险,由于建造者独立,

使用场景:

1.相同的方法,不同的执行顺序要产生不同的事件结果时
2.多个部件或零件可以装配到一个产品中,但产生运行结果又不相同时
3.产品类非常复杂,或产品类中的调用顺序不同产生不同的效能就很适合用
4.创建对象过程中用到了系统中一些其他对象,而这些对象有不易获得时,就可以使用建造者模式封装这个过程

跟工厂模式的区别:更加关心零件类型和装配工艺,而工厂方式更注重创建

Java的实践demo:

package DesignPattern.BuilderPattern;
//抽象建造者
public abstract class Builder {//设置产品不同部分,以获得不同的产品public abstract void setPart();//构建产品public abstract Product buildProduct();
}

产品创建类

package DesignPattern.BuilderPattern;public class ConcreteProduct extends Builder {private Product product= new  Product();@Overridepublic void setPart() {// TODO Auto-generated method stub//产品类内的逻辑处理}@Overridepublic Product buildProduct() {// TODO Auto-generated method stubreturn product;}}

导演类

package DesignPattern.BuilderPattern;//导演类
public class Director {private Builder builder = new ConcreteProduct();public Product getAProduct(){builder.setPart();return builder.buildProduct();}
}

产品类

package DesignPattern.BuilderPattern;
//产品类
public class Product {public void doSomething(){//独立业务处理System.out.print("Product doSomething");}
}

使用调用

import java.io.*;
import DesignPattern.BuilderPattern.*;public class JavaLanguageStudy {//yanruTODO程序入口public static void main( String args[]){//System.out.print("Hello java");//建造者模式Director dir = new Director();dir.getAProduct().doSomething();}
}

代理模式(Proxy Pattern)

定义:又叫委托模式,为其他对象提供一种代理以提控制对这个对象的访问,提供更好的访问控制。

包含的三个主题:

1.抽象主题角色:抽象类或接口
2.具体主题角色:被委托的角色
3.代理主题角色:负责对真实角色的应用

扩展部分:
虚拟代理:在需要的地方才去初始化被代理对象,避免大量初始化带来的额外消耗
动态代理:没太看懂demo???涉及到面向切面编程概念
面向切面(AOP)需要搞懂的东西:切面,切入点,通知,织入,yanruTODO待查询

原型模式(Prototype Pattern)

定义: 不通过new而通过复制来产生新对象的模式叫原型模式。用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象

模式应用:

(我突然开始强迫自己写英文了,由于写中文的markdown不知为什么卡的要死)

advantange:

1.copy binary stram and performance is higher than new a object.
2.constructor won’t be executed and this is a disadvantage

usage scenario:

1.if init a class needs much resource,data or hardware.

2.if new object frequently access data.

3.if some other object type needs to modify current object

4.this pattern is used frequently in Java,cause Java Object Class has itself clone(),I don’t know how’s it work in C#

深拷贝和浅拷贝(shallow copy and deep copy)的概念:
浅拷贝:Java的Object类提供的clone()只拷贝本对象,对其内部数组引用对象都不拷贝,还是指向原对象内存地址,这种拷贝就叫浅拷贝。

(需要注意Java中想使用clone()方法的话成员变量就不要用final关键字)
此外,在C#中,没有默认拷贝方法,对象赋值

TestClass b = new TestClass();
TestClass a = new TestClass();
a = b;

结果将导致a依然是指向b的引用,并不会复制出一个新的b,这种情况下,想要真正的复制一个a,只能像Java重写复制那样每个对象成员都单独赋值。

深拷贝:你拷贝你的,我拷贝我的,两个对象之间修改没有相互影响到,有点像拷贝值而不是引用,浅拷贝的复制对象其实依然指向原引用。

《设计模式之禅》读书笔记之C#版-创建类模式相关推荐

  1. 设计模式之禅读书笔记—行为类模式

    设计模式之禅读书笔记-行为类模式 PDF下载地址 责任链模式 命令模式 解释器模式 迭代器模式 中介者模式 备忘录模式 观察者模式 状态模式 策略模式 模板方法模式 访问者模式 责任链模式 定义:使多 ...

  2. 设计模式之禅读书笔记

    >设计原则< >Single Responsibility Principle(单一职责原则)类只有一个修改的原因. ●类的复杂性降低,实现什么职责都有明确的定义. ●可读性高 ●可 ...

  3. 设计模式之禅读书笔记1

    原型模式 实现Cloneable接口并重写clone()方法,就完成了原型模式. 通用源码: public class ProtoTypeClass implements Cloneable{@Ove ...

  4. 《设计模式之禅》笔记序言(附源码链接)

    <设计模式之禅>笔记序言(附源码链接) GitHub链接 2021年9月初,我下定决心要从书本出发,建立自己的技术栈基础体系.在此过程中,从阅读的部分书籍的源代码导读中,我发现其中有迹可循 ...

  5. 设计模式之美读书笔记

    目录 设计模式之美 读书笔记5- 哪些代码看似面向对象,实际是面向过程编程? 读书笔记4- 封装.抽象.继承.多态分别解决了什么编程问题? 读书笔记3- 我们在讨论面向对象的时候,主要说的是什么? 读 ...

  6. Redis 设计与实现 读书笔记(菜鸟版)

    Redis 设计与实现 读书笔记(简略版) 写在前面 第一章(内部数据结构) SDS List Dictionary Rehash Rehash 与 COW 渐进式Rehash 字典收缩 Skipli ...

  7. JavaScript设计模式读书笔记(一)= 创建型设计模式

    全系列目录 JavaScript设计模式读书笔记(一)=> 创建型设计模式 JavaScript设计模式读书笔记(二)=> 结构型设计模式 JavaScript设计模式读书笔记(三)=&g ...

  8. 创建类模式(读书笔记)

    最近在读秦小波写的设计模式之禅这本书,创建类模式读完了,现在做一个读书笔记总结.创建类模式包括单例模式.原型模式.工厂方法模式.抽象工厂模式.建造者模式,它们都能提供对象的创建和管理职责. 单例模式( ...

  9. 设计模式之原型法(ProtoType)----对象创建型模式

    设计模式之原型法(ProtoType)----对象创建型模式 1.意图 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.适用性 1)当要实例化的类是在运行时刻指定时,例如,通过动 ...

最新文章

  1. 小白给小白详解维特比算法(二)
  2. 居家学习的核心操作准则:45分钟的专注
  3. vb.net 机器学习-候选消除法
  4. P2082 区间覆盖(加强版)
  5. 性能优化之图片懒加载
  6. layui 表单动态添加、删除input框
  7. 信息学奥赛一本通 1135:配对碱基链 | OpenJudge NOI 1.7 07
  8. asp.net findcontrol html控件,c# – FindControl找不到控件
  9. JAVA IO基本知识
  10. 黄光裕:力争用未来18个月的时间 使企业恢复原有的市场地位
  11. postgre查询表最后更新日期_Power BI 10月份功能更新浅译
  12. vc mscomm串口通信使用了CButtonST按钮类软件分析
  13. SSD目标检测算法生成8732个先验框
  14. 惠普179fnw打印机使用说明_惠普179fnw驱动下载
  15. PyQt5项目:网速监控器
  16. 软件开发平台流辰信息如何为客户分忧解难?
  17. steam饥荒存档备份_如何查找和备份您的Steam屏幕截图
  18. Pet Peeve 是什么?
  19. 2021年G2电站锅炉司炉最新解析及G2电站锅炉司炉找解析
  20. python怎么定义int变量_Python 变量类型 | 菜鸟教程

热门文章

  1. 【Python】对Excel数据进行批量操作
  2. Template 基础篇-函数模板
  3. SVG实例详解系列(一)(svg概述、位图和矢量图区别(图解)、SVG应用实例)
  4. 2022年全国大学生数学建模竞赛E题目-小批量物料生产安排详解+思路+Python代码时序预测模型(一)
  5. Mac 下安装运行Rocket.chat
  6. [教程] 手把手教你如何安装Google Play框架服务不闪退
  7. Android毕业项目基于Uniapp+SSM实现的移动端的家庭客栈管理系统实现的App计算机毕业论文及毕业设计题目
  8. [经验栈]C#与泰克示波器(Tektronix oscilloscope)MSO64通信操作
  9. ARM最高处理器架构:cortex-a57 哪年能出来?
  10. java制作一个应用程序_一个制作java小应用程序的全过程