1.工厂模式
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
步骤 1:
创建一个接口:
public interface Shape {
void draw();
}
步骤 2:
创建实现接口的实体类。
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
步骤 3:
创建一个工厂,生成基于给定信息的实体类的对象。
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
步骤 4:
使用该工厂,通过传递类型信息来获取实体类的对象。
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//获取 Rectangle 的对象,并调用它的 draw 方法
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取 Square 的对象,并调用它的 draw 方法
Shape shape3 = shapeFactory.getShape("SQUARE");
//调用 Square 的 draw 方法
shape3.draw();
}
}
2.抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂,它提供了一种创建对象的最佳方式。
工厂与抽象工厂的区别:
一个使用继承,一个使用组合。
一个只创建一个产品,另一个创建一个系列产品。
一个使用子类创建的具体类型,另一个的方法用于创建产品。
3.单例模式
双检锁/双重校验锁(DCL,即 double-checked locking)
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
4.策略模式
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
扩展性良好,增加一个策略只需实现接口即可
接口:抽象策略角色,是对策略、算法抽象,通常为接口
public interface Strategy {
public int doOperation(int num1, int num2);
}
实现类:用于实现抽象策略中的操作,即实现具体的算法
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
创建Context类:Context封装角色,起承上启下的作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
}
}
5.代理模式
静态代理的代理对象和被代理对象在代理之前就已经确定,它们都实现相同的接口或继承相同的抽象类。
JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用业务方法前调用InvocationHandler 处理。代理类必须实现 InvocationHandler 接口
JDK 动态代理的步骤
1、编写需要被代理的类和接口
2、编写代理类,需要实现 InvocationHandler
接口,重写 invoke()
方法;
3、使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
动态创建代理类对象,通过代理类对象调用业务方法。
interface DemoInterface {
String hello(String msg);
}
class DemoImpl implements DemoInterface {
@Override
public String hello(String msg) {
System.out.println("msg = " + msg);
return "hello";
}
}
class DemoProxy implements InvocationHandler {
private DemoInterface service;
public DemoProxy(DemoInterface service) {
this.service = service;
}
@Override
public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
System.out.println("调用方法前...");
Object returnValue = method.invoke(service, args);
System.out.println("调用方法后...");
return returnValue;
}
}
public class Solution {
public static void main(String[] args) {
DemoProxy proxy = new DemoProxy(new DemoImpl());
DemoInterface service = Proxy.newProxyInstance(
DemoInterface.class.getClassLoader(),
new Class<?>[]{DemoInterface.class},
proxy
);
System.out.println(service.hello("呀哈喽!"));
}
}
调用方法前...
msg = 呀哈喽!
调用方法后...
hello
6.装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。
RedShapeDecorator是实现了ShapeDecorator的实体类。
DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。
//基础接口
public interface Component {
public void biu();
}
//具体实现类
public class ConcretComponent implements Component {
public void biu() {
System.out.println("biubiubiu");
}
}
//装饰类
public class Decorator implements Component {
public Component component;
public Decorator(Component component) {
this.component = component;
}
public void biu() {
this.component.biu();
}
}
//具体装饰类
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
public void biu() {
System.out.println("ready?go!");
this.component.biu();
}
}
//使用装饰器
Component component = new ConcreteDecorator(new ConcretComponent());
component.biu();
//console:
ready?go!
biubiubiu
7.适配器模式
定义一个包装类,用于包装不兼容接口的对象
把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。
原本由于接口不兼容而不能一起工作的那些类可以在一起工作
步骤1: 创建Target接口;
public interface Target {
//这是源类Adapteee没有的方法
public void Request();
}
步骤2: 创建源类(Adaptee) ;
public class Adaptee {
public void SpecificRequest(){
}
}
步骤3: 创建适配器类(Adapter)
//适配器Adapter继承自Adaptee,同时又实现了目标(Target)接口。
public class Adapter extends Adaptee implements Target {
//目标接口要求调用Request()这个方法名,但源类Adaptee没有方法Request()
//因此适配器补充上这个方法名
//但实际上Request()只是调用源类Adaptee的SpecificRequest()方法的内容
//所以适配器只是将SpecificRequest()方法作了一层封装,封装成Target可以调用的Request()而已
@Override
public void Request() {
this.SpecificRequest();
}
}
8.模板模式
定义一个模板结构,将具体内容延迟到子类去实现。
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行