设计模式
设计模式(Design pattern):代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
设计模式遵循的原则有6个
1、开闭原则(Open Close Principle)
对扩展开放,对修改关闭。
2、里氏代换原则(Liskov Substitution Principle)
只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
使用多个隔离的接口来降低耦合度。
5、迪米特法则(最少知道原则)(Demeter Principle)
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。
1.工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
优点:
1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口
缺点:
1、 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,
2、 在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事
简单工厂模式:就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例
示例代码:
步骤一:创建一个接口/抽象类和抽象方法
package com.rj.bd.factorypattern;
/**
* @desc 面条的抽象类(基类)
* @author
* @time 2018-11-9 上午08:24:45
* */
public abstract class Noodels {
public abstract void kindsOfNoodle();//面条的种类
}
步骤二:创建实现类:
package com.rj.bd.factorypattern;
/**
* @desc 炒类类
* @author
* @time 2018-11-9 上午08:29:08
* */
public class ChaoMian extends Noodels {
@Override
public void kindsOfNoodle()
{
System.out.println("此时创造的是:炒面");
}
}
package com.rj.bd.factorypattern;
/**
* @desc 兰州拉面类
* @author
* @time 2018-11-9 上午08:27:27
* */
public class LanZhouLaMian extends Noodels {
@Override
public void kindsOfNoodle()
{
System.out.println("此时创造的面条为:兰州拉面");
}
}
package com.rj.bd.factorypattern;
/**
* @desc 泡面类
* @author
* @time 2018-11-9 上午08:28:25
* */
public class PaoMian extends Noodels {
@Override
public void kindsOfNoodle()
{
System.out.println("此时创造的是:泡面");
}
}
步骤三:创建简单工厂对象类
package com.sj.bd.mds;
/**
@desc 简单工厂类
@author
@time 2018-08-30
*/
public class SimpleNoodlesFactory {
public static final int TYPE_LM = 1;//兰州拉面
public static final int TYPE_PM = 2;//泡面
public static final int TYPE_CM = 3;//炒面
```
public static Noodles createNoodles(int type) {
case PM:
return new PaoMian();
case LM:
return new LanZhouLaMian();
case CM:
return new ChaoMian();
default:
return new ChaoMian();//默认为炒面类
}
```
}
步骤四:测试类
package com.sj.bd.mds;
/**
* @desc 测试类:测试简单工厂
* @author
* @time 2018-08-30
*
*/
public class CeShi {
public static void main(String[] args) {
Noodels noodel = SimpleNoodelFactory.getNoodels(SimpleNoodelFactory.LM);//此时指出本次创建的面条是哪一类的
noodel.kindsOfNoodle();
}
}
2.代理模式
2.1静态代理
静态代理:所谓静态代理就是自己要为要代理的类写一个代理类,或者用工具为其生成的代理类,总之,就是程序运行前就已经存在的编译好的代理类
特点:不灵活,但是清楚的知道代理类是什么/哪个
2.2动态代理
2.2.1JDK动态代理: JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。我们需要做的,只需指定代理类的预处理、调用后操作即可
简而言之:就是通过绑定接口与实现类,进而实现代理的
步骤:
1)首先,定义业务逻辑接口
2)然后,实现业务逻辑接口创建业务实现类
3)最后,实现 调用管理接口InvocationHandler 创建动态代理(工具)类
4)在使用时,首先创建一个业务实现类对象和一个代理类对象,然后定义接口引用(这里使用向上转型)并用代理对象.bind(业务实现类对象)的返回值进行赋值。最后通过接口引用调用业务方法即可。(接口引用真正指向的是一个绑定了业务类的代理类对象,所以通过接口方法名调用的是被代理的方法们)
2.2.2cglib代理:cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理
简而言之:对指定的目标类生成一个子类,并覆盖其中方法实现增强,进行代理的
备注:要想使用cglib代表,则必须额外的引入新的jar包:asm和cglib
PS:sping-core.jar包含了以上二者
3.单例模式
单例模式确保某个类只有一个实例,而且自动实例化并向整个系统提供这个实例。
单例模式特点:
1、单例类只能有一个实例。
2、单例类必须自创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例
单例模式的优缺点:
优点:该类只存在一个实例,节省系统资源;对于需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
缺点:不能外部实例化(new),调用人员不清楚调用哪个方法获取实例时会感到迷惑,尤其当看不到源代码时
单例模式分为懒汉式单例和饿汉式单
懒汉式:第一次调用的时候才初始化
饿汉式:类加载的时候就初始化实例
4.策略模式
1.策略模式:(Pattern:Strategy)属于行为型模型,是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化
-------策略模式可以替换掉多个if…elseif…elseif…,-------
2.策略模式包含的角色及其职责
1)抽象策略角色[Strategy]:策略类,定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,
Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
2) 具体策略类[ConcreteStrategy]:实现了Strategy定义的接口,包装了相关的算法和行为,提供具体的算法实现。
3)上下文角色[Context]:持有一个策略类的引用,最终给客户端调用。
①需要使用ConcreteStrategy提供的算法。
②内部维护一个Strategy的实例。
③负责动态设置运行时Strategy具体的实现算法。
④负责跟Strategy之间的交互和数据传递。
3.策略模式的优缺点:
优点:
1)策略模式完美体现类开闭原则,扩展性非常好;
2)使用策略模式,可以避免大量判断逻辑代码;
缺点:
1)客户端需要知道所有策略类,自行决定使用哪一种策略;
2)当有新策略产生时需要增加一个策略类,导致系统的类会越来复杂;
4.1没有策略模式
package com.rj.bd.models.strange;
/**
@desc 多个if...elseif...(没有使用策略模式)
@author
@time 2019-11-02
*/
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入出行的方式:");
Scanner cin=new Scanner(System.in);
String fs=cin.nextLine();
if (fs.equals("汽车"))
{
System.out.println("出现的方式为:"+fs);
}
else if (fs.equals("火车"))
{
System.out.println("出现的方式为:"+fs);
}
else if (fs.equals("飞机"))
{
System.out.println("出现的方式为:"+fs);
}
/**
else if (fs.equals("轮船"))
{
System.out.println("出现的方式为:"+fs);
}
**/
}
}
PS:如果没有使用策略模式的话那么我们每增加一种新的出现方式,那么就需要重新打开代码,小心翼翼的打开判断进行修改
4.2使用策略模式
IStrategy.java
package com.rj.bd.models.strange;
/**
@desc 策略接口
@author
/
public interface IStrategy {
public void travelWay(String way);//出行的方式
}`
CarImpl.java
package com.rj.bd.models.strange;
/**
-
@desc 出行方式为汽车
-
`@author
-
@time 2019-11-02
*/
public class CarImpl implements IStrategy {
@Override
public void travelWay(String way) {
System.out.println("出行方式为:"+way);
}
}
PlaneImpl.java
package com.rj.bd.models.strange;
/**
-
@desc 飞机
-
@author
-
@time 2019-11-02
*/
public class PlaneImpl implements IStrategy {
@Override
public void travelWay(String way) {
System.out.println("出行方式为:"+way);
}
}
StrategyContext.java
package com.rj.bd.models.strange;
/**
@desc 策略内容
@author
@time 2019-11-02
*/
public class StrategyContext {
public IStrategy strategy;
//策略内容的有参数构造器
public StrategyContext(IStrategy strategy) {
this.strategy = strategy;
}
/**
@desc 为当前的用户设置出行的方式
*/
public void travelWayForCurrentUser(String way)
{
strategy.travelWay(way);
}
}
Test02.java
package com.rj.bd.models.strange;
import java.util.Scanner;
/**
-
@desc 测试类:测试策略模式
-
@author
-
@time 2019-11-02
*/
public class Test02 {
public static void main(String[] args) {
System.out.println(“请输入出行的方式…”);
Scanner cin=new Scanner(System.in);
String way=cin.nextLine();``
StrategyContext strategyContext=new StrategyContext(new CarImpl());
strategyContext.travelWayForCurrentUser(way);
``
}
}