设计模式六原则
- 单一原则
- 里氏替换原则
- 依赖倒置原则-具体依赖抽象
- 接口隔离原则
- 开闭原则-通过扩展行为实现新的需求而不是修改原有代码
- 迪米特原则
设计模式
工厂模式
定义:由工厂类依据用户的输入场景对同一个依赖对象进行不同的实例化。
分类
简单工厂方法
1. 特征: 追加新的实现类时,其必须在工厂类中添加新追加的场景所对应的实例化对象。
2. 不足: 违背了开闭原则
工厂模式模型
1. 解决工厂方法的不足,新构建实例化对象时,无需再对于工厂类进行实例化对象追加逻辑。只需 要构建新的工厂类
示例:
public abstract class Operation {
private int numberA;
private int numberB;
/**
* Field/属性 numberA
*
* @return 返回属性 numberA
*/
public int getNumberA() {
return numberA;
}
/**
* @param numberA 设定属性 numberA
*/
public void
setNumberA(int numberA) {
this.numberA = numberA;
}
/**
* Field/属性 numberB
*
* @return 返回属性 numberB
*/
public int getNumberB() {
return numberB;
}
/**
* @param numberB 设定属性 numberB
*/
public void
setNumberB(int numberB) {
this.numberB = numberB;
}
public abstract int getResult();
}
////////////////////////////////////////////////////////////////////
public class OperationFactory {
public static Operation createOperation(String operationSymbol) {
switch (operationSymbol) {
case "+":
return new AddOperation();
case "-":
return new MinusOperation();
case "*":
return new MultipleOperation();
case "/":
return new DivisionOperation();
default:
return null;
}
}
}
简单工厂模型的UML图例
classDiagram
Operation <|-- qqq
Operation <|-- 111
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
抽象工厂模式
定义:围绕一个工厂创建不同的工厂。即就是,其提供了创建工厂的工厂
使用场景:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品
组成元素
- 抽象工厂-用于依据不同的条件实例化不同的工厂系列
- 工厂系列-表示同一产品族的工厂
- 工厂产品-产品族工厂所生产的产品
实例图示
实例代码:
///////////////////////////////////////////////////////
// 基本产品抽象
public abstract class Shape {
protected abstract void draw();
}
public abstract class Color {
protected abstract void fill();
}
// 基本产品的系列
public class Rectangle extends Shape {
@Override
protected void draw() {
System.out.println("draw a rectangle");
}
}
public class CirCle extends Shape {
@Override
protected void draw() {
System.out.println("draw a Circle");
}
}
public class Green extends Color {
@Override
protected void fill() {
System.out.println("fill with green");
}
}
public class Yellow extends Color {
@Override
protected void fill() {
System.out.println("fill with yellow");
}
}
// Base Factory
public abstract class BaseFactory {
public abstract Shape getShape(String shapeType);
public abstract Color getColor(String colorType);
}
// 系列产品工厂
public class ShapeFactory extends BaseFactory {
@Override
public Shape getShape(String shapeType) {
switch (shapeType.toLowerCase()) {
case "circle":
return new CirCle();
case "rectangle":
return new Rectangle();
default:
return null;
}
}
@Override
public Color getColor(String colorType) {
return null;
}
}
public class ColorFactory extends BaseFactory {
@Override
public Shape getShape(String shapeType) {
return null;
}
@Override
public Color getColor(String colorType) {
switch (colorType.toLowerCase()){
case "green":
return new Green();
case "yellow":
return new Yellow();
default:
return null;
}
}
}
// 工厂系列
public class ProducerFactory {
public static BaseFactory createFactory(String factoryType) {
if (factoryType.toLowerCase().equals("shap")) {
return new ShapeFactory();
} else {
return new ColorFactory();
}
}
}
单例模式
定义: 类对象的实例由本身创建,且所创建的对象有且仅有一个。
使用场景:一个全局使用的类频繁地创建与销毁
实例代码
public class LazySingleObject {
private static volatile LazySingleObject lazySingleObject;
private LazySingleObject(){}
public static synchronized LazySingleObject getInstance(){
if (lazySingleObject==null) {
lazySingleObject =new LazySingleObject();
}
return lazySingleObject;
}
}
public class StraveSingleObject {
private final static StraveSingleObject straveSingleObject = new StraveSingleObject();
private StraveSingleObject(){}
public static StraveSingleObject getInstance(){
return straveSingleObject;
}
}
构造器模式
定义:构建复杂对象,该复杂对象有多个依赖对象组成,分步骤创建复杂对象。使用相同的创建过程构建不同的对象。
特点:将一个复杂的对象分解了多个简单的对象,然后一步步的构建成。达到了将变与不变相分离,即组成部分是不变的,但是是每一部分又可以达到灵活选择.
适用场景:使用生成器模式可避免 “重叠构造函数 (telescoping constructor)” 的出现
补充说明:Builder 模式和工厂模式的关注点是不同的,Builder 模式更注重产品零件的组装过程,而工厂模式更加注重产品零件的创建过程。
角色:
- 产品角色 (Product):是包含多个组成部件的复杂对象,而由具体的建造者来创建其各自的部件。 只是声明产品应该有的属性 class Product { private String partA; private String partB; private String partC; public void setPartA(String partA){ this.partA=partA; } public void setPartB(String partB){ this.partB=partB; } public void setPartC(String partC){ this.partC=partC; } public void show(){ //显示产品的特性 } }
* 抽象建造者 (Builder):一个包含创建产品各个子部件抽象方法的一个接口,通常还包含返回产品的方法 getProduct ()
abstract class Builder { //创建产品对象 protected Product product=new Product(); public abstract void buildPartA(); public abstract void buildPartB(); public abstract void buildPartC(); //返回产品对象 public Product getResult(){ return product; } }
产品作为基础属性,同时存在多个抽象方法用于对产品所依赖的部分进行抽象的构建声明。
* 具体构造者 (Concrete Builder):用来实现 Builder 接口,完成复杂产品各个子部件的具体创建方法
实现抽象的builder 用于具体实例化各个依赖成员。
public class ConcreteBuilder extends Builder { public void buildPartA() { product.setPartA("建造 PartA"); } public void buildPartB() { product.setPartA("建造 PartB"); } public void buildPartC() { product.setPartA("建造 PartC"); } }
* 指挥者 (Director):完成复杂对象的创建以及装配,指挥中不会涉及具体产品的信息。
产品的构建与组装
```java
class Director {
private Builder builder;
public Director(Builder builder) { this.builder=builder; }
//产品构建与组装方法
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
原型模式
定义: 依据类对象构建相同的对象,而不用关注对象所关联的类
适用场景:复制一些对象, 同时又希望代码独立于这些对象所属的具体类,可以使用原型模式。
原型模式为客户端代码提供一个通用接口, 客户端代码可通过这一接口与所有实现了克隆的对象进行交互, 它也使得客户端代码与其所克隆的对象具体类独立开来。
角色:
- 客户端:客户端提出创建对象的请求。
public class PrototypePatternTest{
public static void main(String[] args) throws CloneNotSupportedException { Movie moviePrototype = new Movie();
Movie movie = moviePrototype.clone();
System.out.println(movie);
Album albumPrototype = new Album();
Album album = albumPrototype.clone();
System.out.println(album);
Show showPrototype = new Show();
Show show = showPrototype.clone();
System.out.println(show);
}
}
- 原型接口:这是一个抽象角色,通常是 Java 接口和 Java 抽象类。此角色给出所有的具体原型类(Concrete Prototype)的接口。在 Java 中通常是 Cloneable 接口
public interface PrototypeCapable extends Cloneable {
PrototypeCapable clone() throws CloneNotSupportedException;
}
- 原型类:被复制的对象。此角色需要实现抽象原型角色的接口
public class Movie implements PrototypeCapable {
private String name = "钢铁侠";
@Override
public Movie clone() throws CloneNotSupportedException {
return (Movie)super.clone();
}
@Override public String toString() {
return "Movie{name='" + name + "'}";
}
}
public class Show implements PrototypeCapable {
private String name = "维多利亚的秘密";
@Override public Show clone() throws CloneNotSupportedException {
return (Show)super.clone(); }
@Override public String toString() {
return "Show{name='" + name + "'}";
}
}
结构型设计模式
适配器模式
定义:一种中间件,将两种不匹配的东西进行匹配关联。
使用场景:
- 使用某个类但其与交互的接口不兼容的场合
- 子类在同一个继承体系下,但新增的子类有部分需要追加的新功能。为维护子类的一致性。通过适配器的模式将需要新追加的功能进行统一封装。
角色:
1.适配器 2.不兼容的两个要匹配的对象
实际应用场景
1.背景:高考查询成绩系统,考生查看成绩时需要三个请求参数。学号ID,学校名称,学校所在的省。 2.需求:学校X为本校学生开发的成绩查询系统,为提高效率。学生只需要提供学号ID.
实现方式
因学校固定:对于该学校的同学其学校信息,学校所在省信息均一致。因此,使用接口适配模式,对于原有的只提供ID的接口在适配器中进行参数补充。从而能够使学生只提供ID即可获取器对应的成绩信息。
桥接模式
参考说明
定义:用于把抽象化与实现化解耦,使得二者可以独立变化。
使用场景:
-
实现系统可能有多个角度分类,每一种角度都可能变化
-
拆分或重组一个具有多重功能的庞杂类 (例如能与多个数据库服务器进行交互的类),可以使用桥接模式。
-
几个独立维度上扩展一个类。
-
运行时切换不同实现方法。
设计意图
桥接模式不是将两个不相干的类链接,而是将一个需要多维度变化的类拆分成抽象部分和实现部分,并且在抽象层对两者做组合关联,是用组合的方式来解决继承的问题。举个例子,如果一个类在两个维度分别有 m 和 n 种变化,采用继承的方式就需要扩展出 m*n 个子类,且一个维度每增加一种变化就多出另一个维度变化总数的子类;如果将两个维度拆分再组合,加起来也只有 m+n 个子类,且每个维度独立扩展,一个维度增加一种变化只需要增加1个子类。
实例分析
需求:开发一个跨平台的音乐播放器,它可以在 Windows、Mac、Linux 等多种操作系统上运行 实现:
- 一个抽象类
MediaPlayer,它定义了播放器的基本接口和方法
public abstract class MediaPlayer {
protected OperatingSystem operatingSystem;
public MediaPlayer(OperatingSystem operatingSystem) {
this.operatingSystem = operatingSystem;
}
public abstract void play();
}
OperatingSystem是一个抽象类,定义了不同操作系统之间的共同特征:
public abstract class OperatingSystem {
public abstract String getName();
}
- 不同操作系统的具体实现类,例如
Windows、Mac 和 Linux:
public class Windows extends OperatingSystem {
@Override
public String getName() {
return "Windows";
}
}
public class Mac extends OperatingSystem {
@Override
public String getName() {
return "Mac";
}
}
public class Linux extends OperatingSystem {
@Override
public String getName() {
return "Linux";
}
}
- 不同操作系统下的具体播放器实现类,例如
WindowsMediaPlayer、MacMediaPlayer 和 LinuxMediaPlayer:
public class WindowsMediaPlayer extends MediaPlayer {
public WindowsMediaPlayer(OperatingSystem operatingSystem) {
super(operatingSystem);
}
@Override
public void play() {
System.out.println("Playing on " + operatingSystem.getName() + " using WindowsMediaPlayer.");
}
}
public class MacMediaPlayer extends MediaPlayer {
public MacMediaPlayer(OperatingSystem operatingSystem) {
super(operatingSystem);
}
@Override
public void play() {
System.out.println("Playing on " + operatingSystem.getName() + " using MacMediaPlayer.");
}
}
public class LinuxMediaPlayer extends MediaPlayer {
public LinuxMediaPlayer(OperatingSystem operatingSystem) {
super(operatingSystem);
}
@Override
public void play() {
System.out.println("Playing on " + operatingSystem.getName() + " using LinuxMediaPlayer.");
}
}
- 在
mac平台下可以这么调用
public class BridgeTest {
public static void main(String\[] args) {
MediaPlayer player = new MacMediaPlayer(new Mac());
player.play();
// Playing on Mac using MacMediaPlayer.
}
}
结构型模式-组合模式
定义:将对象组合为一种具有树状层次结构的模型。用来表示部分-整体,确保客户端在访问组合对象与组合对象中存在的组合元素的一致性。
使用场景:
- 实现树状对象结构, 可以使用组合模式
- 客户端代码以相同方式处理简单和复杂元素,即就是隐藏组合对象与单个对象的不同,用统一的接口使用组合结构中的所有对象的场合.
目的
客户端不再区分操作的是组合对象还是叶子对象而是以统一的方式来操作
角色
- 抽象接口-单一元素实现该接口
- 单一元素
- 组合元素
- 客户端
说明:
组合图形CompoundGraphic是一个容器, 可以由多个包括容器在内的子图形构成.组合图形与简单图形拥有相同的方法.组合容器并不完成具体的工作,而是有其传递给具体的子元素进行实施。
客户端有需求时,可以通过容器的公共接口实现与组合容器进行交互,实现与单一元素的强解耦。
// 组件接口会声明组合中简单和复杂对象的通用操作。
interface Graphic is
method move(x, y)
method draw()
// 叶节点类代表组合的终端对象。叶节点对象中不能包含任何子对象。叶节点对象
// 通常会完成实际的工作,组合对象则仅会将工作委派给自己的子部件。
class Dot implements Graphic is
field x, y
constructor Dot(x, y) { …… }
method move(x, y) is
this.x += x, this.y += y
method draw() is
// 在坐标位置(X,Y)处绘制一个点。
// 所有组件类都可以扩展其他组件。
class Circle extends Dot is
field radius
constructor Circle(x, y, radius) { …… }
method draw() is
// 在坐标位置(X,Y)处绘制一个半径为 R 的圆。
// 组合类表示可能包含子项目的复杂组件。组合对象通常会将实际工作委派给子项
// 目,然后“汇总”结果。
class CompoundGraphic implements Graphic is
field children: array of Graphic
// 组合对象可在其项目列表中添加或移除其他组件(简单的或复杂的皆可)。
method add(child: Graphic) is
// 在子项目数组中添加一个子项目。
method remove(child: Graphic) is
// 从子项目数组中移除一个子项目。
method move(x, y) is
foreach (child in children) do
child.move(x, y)
// 组合会以特定的方式执行其主要逻辑。它会递归遍历所有子项目,并收集和
// 汇总其结果。由于组合的子项目也会将调用传递给自己的子项目,以此类推,
// 最后组合将会完成整个对象树的遍历工作。
method draw() is
// 1. 对于每个子部件:
// - 绘制该部件。
// - 更新边框坐标。
// 2. 根据边框坐标绘制一个虚线长方形。
// 客户端代码会通过基础接口与所有组件进行交互。这样一来,客户端代码便可同
// 时支持简单叶节点组件和复杂组件。
class ImageEditor is
field all: CompoundGraphic
method load() is
all = new CompoundGraphic()
all.add(new Dot(1, 2))
all.add(new Circle(5, 3, 10))
// ……
// 将所需组件组合为复杂的组合组件。
method groupSelected(components: array of Graphic) is
group = new CompoundGraphic()
foreach (component in components) do
group.add(component)
all.remove(component)
all.add(group)
// 所有组件都将被绘制。
all.draw()
结构型模式-装饰器模式
定义:向一个现有的对象添加新的功能,同时又不改变其结构。装饰者可以在所委托的被装饰者行为之前或之后加上自己的行为,以达到特定的目的。
场景:
- 无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为, 可以使用装饰模式。
- 用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式
角色
创建一个 Shape 接口和实现了 Shape 接口的实体类。而后创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。 RedShapeDecorator 是实现了 ShapeDecorator 的实体类。 DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。
结构模型-外观模式
定义: 外观模式为子系统定义一个统一的接口,以达到简化客户端与子系统之间的交互。为客户端屏蔽子系统的复杂性,同时提高子系统的独立性,灵活性。
作用:外观模式为通过定义一个高层的接口,将子系统中具体的复杂操作进行封装。使其对客户端进行透明。因外观类封装了子系统的所有接口。因此客户端只需要与外观模式进行交互就可完成所有的操作。从而使得客户端更加的简洁,易于维护与升级
使用场景
- 简化客户端与子系统之间的交互时,可以使用外观模式提供一个简单的接口
- 一个系统需要与多个子系统直接进行交互时,可通过外观模式对于各个子系统进行功能封装,从而减少系统与子系统之间的依赖。
- 当需要对于子系统进行复杂的初始化配置时,
组成要素
- 外观(Facade):外观对象是客户端访问子系统的入口。首先负责初始化子系统中的各个对象。而后向外提供一个或多个简单的接口。为客户端调用子系统提供更高层次的接口
- 子系统(sunSystem):子系统是具备完善功能的系统或模块,本身包含了一系列的类对象与方法。对于客户端来说,子系统完全独立。其能够被类,或qi其他应用程序所重用
- 客户端(client):通过外观类访问子系统。客户端进需要向外观类发出请求,外观类会委派一个或者多个子系统访问该请求数据。
UML示例图
classDiagram
class IFacade{
<<Interface>>
}
class FacadeImp{
+ linkeToSubSystem()
+ subSystemOperation()
}
class SubSystem01{
-int num01
-int num02
+int getMultiplication()
}
class SubSystem02{
-int num01
-int num02
+int getSubstraction()
}
class Client
FacadeImp<--Client
IFacade<|..FacadeImp
SubSystem01<..FacadeImp
SubSystem02<..FacadeImp
外观模式在Spring源码中的应用
外观模式在Spring框架中有较为广泛的应用,外观角色CoreContaine提供。
- 获取ApplicationContext实例。
- BeanFactory实例等。
public final class CoreContainer {
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
// 构造函数
public CoreContainer() {}
// 获取 ApplicationContext 实例
public ApplicationContext getApplicationContext() {
return this.applicationContext;
}
// 获取 BeanFactory 实例
public BeanFactory getBeanFactory() {
return this.beanFactory;
}
// 初始化方法
public void init() {
// 初始化 ApplicationContext 实例
this.applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取 BeanFactory 实例
this.beanFactory = this.applicationContext.getBeanFactory();
}
}