本文摘自:http://zz563143188.iteye.com/blog/1847029
一,设计模式的分类
总体来说,设计模式分为三大类:
①创建型模式(5种) :单例模式,工厂方法模式,抽象工厂模式,原型模式,建造者模式。
②结构型模式(7种) :适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
③行为型模式(11种):策略模式,模板方法模式,观察者模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式。
其实还有两类:并发型模式和线程池模式。用一个图片来整体描述下:
二,设计模式的原则
1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
其他详细的。。略。。
本文摘自:http://zz563143188.iteye.com/blog/1847029
===========================================================================
追加一些笔记:
设计模式学习:
①代理模式:代理模式的一种常见的实现方案是,定义一个接口或抽象类,并派生出目标子类,
和代理子类。
重点:我们要操作的是目标子类里的方法,而很多时候,我们需要为目标子类中的方法增加额外的处理,
如果增加日志功能、条件判断等,这时候,就很有必要用到代理类。
代码关键:用代理类同样实现公共接口;并且在构造方法中注入原来接口的实例。【这样我们在构造代理类的时候,可以把原来目标类作为参数传递进去。】
并且在实现接口方法的时候,调用原来目标类的实现方法,并加上自己需要多出来的处理代码。
--------------------
可以看出静态代理类有一个很不爽的缺点:当如果接口加一个方法,所有的实现类和代理类里都需要做个实现。这就增加了代码的复杂度。动态代理就可以避免这个缺点。
动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理
那样每一个方法进行中转。【动态代理似乎使用了反射机制】
而加入反射机制的代理模式,可实现一个公共的代理类,省去我们不少功夫。Java的java.lang.reflect包及其子包中提供了Class、Method、Annotation等有用的类。下面,写个方法代理的类MethodProxy
,实现动态地调用对象的方法。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 方法代理类
* @author rongxinhua
*
*/
public class MethodProxy {
private Class clazz; //对象所属的类
private Object target; //目标对象
private Method method; //目标方法
private Object[] params; //参数数组
@SuppressWarnings("unchecked")
public MethodProxy(Object target, String methodName, Object ... params) {
rebindTarget(target, methodName, params); //设置目标对象与方法
}
/**
* 重新设置目标对象与方法
* @param target
* @param methodName
* @param params
*/
public void rebindTarget(Object target, String methodName, Object ... params) {
this.target = target;
this.clazz = target.getClass();
rebindMethod(methodName, params); //设置目标方法
}
/**
* 重新设置目标方法
* @param methodName
* @param params
*/
public void rebindMethod(String methodName, Object ...params) {
this.params = params;
int paramLength = params.length;
Class[] paramTypes = new Class[paramLength];
for(int i = 0 ; i < paramLength ; i ++ ) {
paramTypes[i] = params[i].getClass();
}
try {
this.method = clazz.getMethod(methodName, paramTypes);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
/**
* 动态调用已绑定的方法
*/
public void doMethod() {
try {
this.method.invoke(target, params);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
这样就可以实现动态地调用某个对象的某个方法了,写个测试代码如下:
public class Manager {
public void say() {
System.out.println("Nobody say nothing");
}
public void love(String boy, String girl) {
System.out.println(boy + " love " + girl);
}
}
我们通过代理类来调用Manager类中的say()和love()方法,测试代码如下:
Manager man = new Manager(); //目标对象
MethodProxy proxy = new MethodProxy(man, "say"); //方法代理对象
proxy.doMethod(); //调用被代理的方法
proxy.rebindMethod("love", "Tom", "Marry"); //重新绑定方法
proxy.doMethod(); //调用被代理的方法
这样就实现了动态代理调用对象的方法,上面代码输出结果就不贴出来了。如果要设置前置通知和后置通知等功能,也很容易实现,只需在“proxy.doMethod()”代码处的前面和后面设置即行。
②回调 callback
回调表示一段可执行逻辑的引用(或者指针),我们把该引用(或者指针)传递到另外一段逻辑(或者方法)里供这段逻辑适时调用。C语言里经常使用函数指针实现回调,C#语言里使用代理delegate
实现,而在java语言里面我们使用内部匿名类实现回调。
【泛型是指能够在运行时动态得到对象类型的一种能力,这样,我们就没有必要每次都写强制类型转换语句了。其实java是在编译时为生成的二进制代码加入强制类型转换的语句,并非真正在运行时得到
对象的类型。】
4.自定义泛型:
4-1.泛型定义在方法上:放之前定义
public <T> void test1(T t){}
public static <T> void test2(T t){}
public <T> int test3(T t){ return 0; }
public <T> List<T> test4(){ return null; }
public static <EE> void test5(EE e){}
4-2.泛型定义在类上:如果一个同时用到同一个泛型那么可以把泛型定义到类上 ,可以声明一个或多个
public class StudentDao<T,E>{
public void test(T t){}
public List<T> test2(){ return null; }
③单例模式,注意将它变成线程安全的。
public class ThreadSafeSingleton{
private static ThreadSafeSingleton threadSafeSingleton;
private ThreadSafeSingleton(){
}
public static ThreadSafeSingleton getInstance(){
if(threadSafeSingleton == null){
threadSafeSingleton = new ThreadSafeSingleton();
}
return threadSafeSingleton;
}
}
但实际上,加上synchronized会使得性能大不如前。但其实使用synchronized关键字对整个getInstance方法进行同步是没有必要的:我们只要保证实例化这个对象的那段逻辑被一个线程执行就可以了,
而返回引用的那段代码是没有必要同步的。修改后的代码:
public class DoubleCheckSingleton{
private volatile static DoubleCheckSingleton instance = null;
private DoubleCheckSingleton(){}
public static DoubleCheckSingleton getInstance(){
if(instance ==null){
synchronized(DoubleCheckSingleton.class){ // synchronize creation block。synchronized关键字包含的一般是变量。
if(instance == null){ // double check if it is created
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
在getInstance方法里面,我们首先判断此实例是否已经被创建了,如果还没有创建,首先使用synchronized同步实例化代码块。在同步代码块里,我们还需要再次检查是否已经创建了此类的实例,这是
因为:如果没有第二次检查,这是有两个线程ThreadA 和Thread B同时进入该方法,它们都检测到instance为null,不管哪一个线程先占据同步锁创建实例对象,都不会阻止另外一个线程继续进入实例化
代码块重新创建实例对象,这样,同样会发生两个实例对象。所以,我们在同步的代码块里,进行第二次判断,判断该对象是否已被创建。 另外:属性instance是被volatile修饰的,因为Volatile具有
synchronized的可见性特点,也就是说线程能够自动发现volatile变量的最新值。这样,如果instance实例化成功,其他线程便能立即发现。
上面的程序只能在java 5以上版本执行,因为之前的版本 java平台的内存模式容许 out-of-order writes。在instance没有完全实例化时,instance变量就可以指向此实例,导致其他线程直接使用了这
个未初始化完成的实例,结果可能引起系统崩溃。
还有一种方法,称为:Initialization on demand holder模式。
public class LazyLoadedSingleton{
private LasyLoadedSingleton(){}
private static class LazyHolder{
private static final LazyLoadedSingleton singletonInstance = new LazyLoadedSingleton();
}
public static LazyLoadedSingleton instance(){ return LazyHolder.sinletonInstance;}
}
JLS保证,上述过程不会发生并发问题,这样就实现了一个 既线程安全又支持延迟加载的单例模式。
如果单例类实现了Serializable接口,这时我们得特别注意,因为我们知道在默认情况下,每次反序列化总会创建一个新的实例对象,这样一个系统会出现多个对象供使用。。。。 我们需要在
readResolve方法里面做文章,此方法在反序列化完成之前被执行,我们在此方法里替换掉反序列化出来的那个新的实例,让其指向内存中的那个单例对象即可,代码如下:
public class SerialibleSingleton implements Serializable{
private static final long serialVersion UID = -23452345234623464634L; // 乱写的数字
static SerialibleSingleton singleton = new SerialibleSingleton();
private SerialibleSingleton(){};
private Object readResolve(){return singelton;}
}
④ 原型模式:prototype。 使用原型实例指定将要创建的对象类型,通过拷贝这个实例创建新的对象。
浅拷贝和深拷贝的概念。浅拷贝只拷贝了对象的引用,而没有在内存中复制对象。 使用java.lang.Cloneable接口
优点:方便实例化,只要复制对象,然后初始化对象,就可以得到你想要的对象,并不需要过多的编程。
⑤ 控制反转IoC
我们经常把控制逻辑写在其他地方(例如Framework)而非客户化的代码里,我们就更专注于客户化的逻辑,也就是说,外部逻辑负责调用我们客户化的逻辑。
控制反转 Inversion Of Control 调用者不再创建被调用者的实例,由spring框架实现(容器创建)所以称为控制反转。
依赖注入: 容器创建好实例后再注入调用者称为依赖注入。【目前分为6类:Setter注入,Constructor注入,Annotation注入,Interface注入,Parameter注入和 其他形式的注入。】
当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,。如果创建被调用者实例的工作不再由
调用者来完成,而是由外部容器完成,因此称为控制反转; 创建被调用者 实例的工作通常由外部容器来完成,然后注入调用者,因此也称为依赖注入
⑥装饰器模式
装饰器模式可以让我们在运行时动态地增加对象的功能,而不影响客户程序的使用。
OCP Open-Closed Principle 开放-封闭原则。软件实体(类,模块,功能等等)应当对外扩展开放,但是对修改关闭。
代理模式和装饰器模式非常相似,很多人甚至把它们看成一种模式。但它们设计目的不同:
代理模式并不实现和目标对象类似的业务功能,而是一些与目标对象功能联系不太紧密的职责,也就是说,二者处理的是不同的问题域。比如权限控制,连接服务器,处理异常,缓存目标对象等,这
些与目标对象的功能不是同一类的;而装饰器对象处理的问题与目标对象处理的问题都是同一问题域,目的是增加目标对象那方面的能力,例如Java IO 的BufferedInputStream和修饰对象InputStream都
是为实现流读取设计的,它使得InputStream可以缓冲读取数据。
装饰器动态地为目标对象添加功能或者减少功能,还可以递归地装饰目标对象,产生叠加的效果,而代理模式不用做此用途。
⑦ 适配器模式: 中国的电器拿到美国去用,如果接口不一样,则可以找一个转换器接在中间
适配器模式和代理模式都是把请求转发给目标对象来处理,但是实现的接口不一样;代理模式的代理类和被代理类(目标类)都实现了相同的接口,而适配器实现新的满足客户类的接口(目标接口),
实现兼容客户类的目的。
⑧ 外观 (Facade) 模式 【外观模式用到了一条非常有用的设计原则:最少知识原则 Least Knowledge Principle 】
在软件设计里,如果软件系统和一些子系统有非常繁复的交互,你可能希望减少和他们之间的交互达到简化的目的,这就使用到了外观模式。外观模式是我们最常使用的设计模式之一,非常直观
和简单,读者可能已经在使用了,只不过不知道它就是外观模式。
⑨ 组合模式。【将对象组合成树形结构来表现部分-整体的层次关系。组合使得客户一致地使用单个对象和组合对象。】
我们在开发过程中经常使用到树形结构,它分为叶子节点和分支节点,客户对象在使用这两种对象时候经常要对他们加以区别,增加了代码的复杂度,也非常容易出错。组合模式围着两种类型提供了
同一的接口,可以让我们像操作叶子节点那样方便地操作分支节点。
对于组合模式来说有两种,我们把对子节点的管理操作(如add,remove和getChild等操作)放在分支类BranchComposite类里,叶子类BranchLeaf看不到这些操作和定义,这种是安全的组合模式,另
外一种叫做透明的安全模式:可以把管理子节点的操作放在 Component,然后让叶子类的这些操作在运行时失效(可以不做任何处理,也可以抛出异常等),这样对客户对象来说,这种方式更加透明。
第四章 (行为模式)包括策略(strategy)模式,状态(State)模式和 观察者(Observer)模式。
⑩策略模式。 我们先给出一条OOP关于封装变化的设计原则:找出你的应用程序变化的那些方面,并把他们和那些不变的部分分开。
GoF 给出的策略模式定义:定义了一组算法,对每一种进行封装,使他们可以相互交换。此模式可以使算法独立于使用它的客户程序而变化。
注意 OOP的另一条设计原则: 优先使用合成而非继承。 OOP的一个重要特点是继承,继承提供了一条避免代码重复的途径,尽管如此,我们还是优先考虑合成,HappyPeople对象合成了Travellable的对
象,这比继承来的更加灵活。
⑾ 状态(State)模式
GoF 给出的定义是:允许一个对象在其内部状态发生变化时改变自己的行为,该对象看起来好像修改了它的类型
(14)观察者模式(Observer)
在股价波动,通知股票持有者的模型中,股票和投资者之间的关系是1:N的关系,当价格发生一定变化时,股票以广播的方式通知投资者,这正是观察者模式,GoF给出的定义如下:
定义了对象之间的一种一对多的依赖关系,这样,当一个对象的状态发生变化时,所有依赖于对象都被通知并自动更新。
上述模式采用的是push方式,即股票把观察者所需要的信息都推给了他们,这里是指把股票价格都推给了目标。另外一种pull方式,即股票在通知观察者时并不传递股票信息,而由观察者显式地查
询股票信息。使用前者时,如果观察者需要获得更多的信息,可能导致观察者接口不能重用;使用后者时,观察者可能不容易知道哪些信息发生了改变。
设计模式终结篇
OOP,它不能解决所有的编程问题,OOP在纵向分解问题方面表现十分出色,但对于水平问题,有点无能为力,AOP能够弥补这方面的不足。我们将在15章介绍时下流行的AOP技术。
了解和使用模式对于开发来说,还远远不够,软件的核心是模型,开发大型的复杂业务的应用,需要精炼的模型,如果模型不够精炼,也不能享受到设计模式带来的好处,在 16章我们将讲解简单介绍
如何提炼模型解决复杂的领域问题。
【总述】
面向对象的开发范式:对象是包含了方法和数据的结构体,这给开发者带来了新的视角去分析问题:
面向对象的最大好处就是封装,让我们再回顾一下这些设计模式都封装了哪些方面:
(1)创建型模式:创建型模式封装了实例化的过程,客户对象不再关心这些创建的细节;应该是用哪个具体类,如何初始化和组装实例。这样,也为实例化提供了很大的灵活性:可以使用克隆的方式
加快创建过程和简化创建细节,也可以根据配置确定实例化的具体类型,还可以根据需要创建的单例对象。
(2)模板方法模式:封装了那些不变的算法步骤,把变化那些部分交给子类去封装,对使用者隐藏了具体的子类型。
(3)装饰器模式:装饰器模式隐藏了被装饰对象;并且,由于装饰对象和被装饰的对象具有相同的接口,客户对象在使用被装饰过的对象和未装饰过的对象时,不需要对他们区别对待,隐藏了装饰器
类型。
(4)代理模式:和装饰器模式一样,隐藏了被代理对象(目标对象),也实现了代理类型的隐藏。
(5)适配器模式:隐藏了被适配的接口/类,客户对象并不知道请求会转发给被适配的对象。
(6)外观模式:隐藏了子系统,封装了外观和子系统之间的复杂交互。
(7)组合模式:实现了叶子类和分支子类的隐藏,客户对象操作叶子对象和分支对象时不需要区别对待。
(8)策略模式:每一具体策略都封装了一个具体的实现算法。
(9)状态模式:每一状态都封装了与一个特定状态相关的行为,Context隐藏了状态接口和实现,客户对象不知道它们的存在。
(10)观察者模式:不同的观察者对变化的处理是不同的,把这些变化封装在不同类型的观察者类型里,由于他们有相同的接口,观察者就能独立于主题而变化。另外如果为主题也抽象了接口,这样观
察者和主题两方面就能独立变化与重用,而不会影响对方。
【OOP强调面向接口和抽象的编程,隐藏了具体的实现,减少了耦合】对象模块化的粒度超过了单个的方法或者结构体,这样,我们更容易把系统分割成易于处理的抽象单元,我们也可以重用和组合这些
功能更强的单元,并隐藏更多的细节,减少程序之间的耦合。 多态可以让我们关心在什么时间去做,而不关心如何去做,因为如何去做可以在后续开发中扩展。多态强调以相同的方式处理不同类型的对
象,而这些对象有什么样的行为却在运行时决定。
一些 软件设计原则
DRY原则: 尽量避免重复,如果你能在你的代码里发现重复,尽快的重构它。
好莱坞原则、控制反转: 这个原则让我们可以很轻松的把可扩展的那部分代码插入到控制程序中去,以完成一个完整的流程,这样,我们就更关注于需要扩展的那部分逻辑开发了。
OCP原则: 软件实体要对修改关闭,对扩展开放,软件开发发展至今,在这方面取得了一些成就。
最少知识原则: 知道的最少,耦合性最弱。
封装变化: 封装那些变化的部分供客户化,让使用者依赖于抽象而非具体,在不影响使用者的前提下扩展系统功能。
优先使用合成而非继承: 尽管继承是一个非常好的重用父类功能、扩展父类功能的方法,但是我们尽量使用合成,有时候二者结合。
Pareto原则: 这条原则不仅仅是我上述讲述的几种表达方式,可以广泛运用到软件开发的其他方面。
相关推荐
《设计模式学习笔记》主要探讨了GOF的23种设计模式以及类设计的基本原则,旨在帮助开发者理解和应用这些经过时间验证的成熟解决方案。设计模式是面向对象软件设计中的核心概念,它们为解决常见的设计问题提供了标准...
Head First 设计模式(高清中文完整版带目录)+附书源码+HeadFirst设计模式学习伴侣.rar 又名: Head First Design Patterns 作者: (美)弗里曼(Freeman,E.) 副标题: Head First Design Patterns 简介 ·····...
HeadFirst设计模式学习伴侣.jpg
这个“设计模式学习ppt”资料包显然是一份面向初学者或大学生的教学资源,通过十四个PPT文件深入浅出地讲解了设计模式的各个方面。 首先,我们来看设计模式的基本概念。设计模式是对在特定上下文中反复出现的问题...
文档中描述的是Java设计模式学习笔记,目前涉及了7种设计模式,但没有具体指明这7种模式是什么,计划后续增加更多的模式。虽然文件内容中存在OCR扫描的识别错误,但不影响我们从整体上把握设计模式的脉络和学习方法...
本资料“java设计模式学习”包含了对设计模式的深入理解和实际应用,通过简单实用的例子,帮助开发者掌握如何在Java项目中运用设计模式。 首先,我们要介绍的是工厂模式。工厂模式是一种创建型设计模式,它提供了一...
在《设计模式学习总结》中,作者通过自己的学习经历和实际应用,分享了对23种经典设计模式的理解和感悟。这篇文档主要讨论了设计模式的概念、作用、应用以及学习设计模式时应注意的误区。 设计模式起源于面向对象...
Java设计模式,解说通俗易懂,推荐新手学习使用,文档中包含类图
本资源"设计模式学习.zip"聚焦于C++编程语言中的设计模式应用,是2017年的一次黑马程序员培训课程的配套代码,旨在帮助学习者通过实际的代码示例来理解和掌握设计模式。 在C++中,设计模式主要分为三大类:创建型...
设计模式学习笔记.ppt 自己写的一点学习笔记。
《设计模式学习系列2设计模式影印版》作为一套学习资料,专注于介绍设计模式的核心理念与实践应用,为读者提供了一个系统性的学习框架。 设计模式主要分为三类:创建型模式、结构型模式和行为型模式。其中,创建型...
本资料包“C# 设计模式学习 源码”包含了作者在学习设计模式过程中的笔记和源码示例,对于想要深入理解C#设计模式的人来说是一份宝贵的资源。 设计模式分为三大类:创建型、结构型和行为型。下面将详细介绍这些类别...
《Head First设计模式学习代码详解》 设计模式是软件工程中的宝贵经验总结,它提供了一套通用的解决方案模板,帮助开发者在面对复杂问题时能够快速有效地进行设计和开发。Head First设计模式是一本非常受欢迎的设计...
"C++设计模式学习框架"是一个专为学习和实践这些模式而构建的资源集合,它涵盖了各种常见的设计模式,帮助开发者深入理解并熟练应用到实际项目中。 设计模式通常分为三类:创建型模式(Creational Patterns)、结构...
本资源“设计模式学习经典篇之菜鸟篇”旨在为初学者提供一个全面而通俗易懂的设计模式学习路径。 设计模式的核心在于重用已验证的解决方案,以提高代码的可读性、可维护性和可扩展性。根据GOF(Gamma, Helm, ...
### Java设计模式学习概述 #### 标题解读 文档标题为“JAVA设计模式学习【技术文档】”,表明这是一份专注于Java语言的设计模式学习资源。设计模式作为软件工程领域的重要组成部分,它提供了一系列面向对象设计问题...
《设计模式学习指南》是一份详细介绍设计模式的资源,旨在帮助开发者理解和掌握设计模式的精髓。 设计模式的学习对于任何想要提升其软件设计能力的人来说都是至关重要的。它可以帮助我们遵循一些核心的设计原则,...
本资源包含的设计模式学习帮助文档和高清中文字幕,旨在提供一个系统化的学习路径,帮助初学者和经验丰富的开发者深入理解并应用设计模式。 设计模式分为三大类:创建型模式、结构型模式和行为型模式。创建型模式...
以下是对“C#设计模式学习笔记”中涉及的一些关键知识点的详细解释。 1. **设计模式的基本概念**: 设计模式是一种在特定上下文中已被证明有效的解决方案模板,它描述了如何在软件设计中解决常见问题。设计模式...