文章目录
GOF(Gang Of Four)—23个设计模式
- 设计模式的分类:
- 创建型:把创建对象的权利交出去,解决的是对象的创建问题。
- 特点:不让用户代码依赖于对象的创建或排列方式,避免用户直接使用new关键创建对象。
- 结构型:描述的是如何将类和对象结合在一起,构成更大的结构。
- 行为型:描述的是算法和对象间职责的分配,不仅描述对象或类的模式,还描述它们之间的通信方式。
- 创建型:把创建对象的权利交出去,解决的是对象的创建问题。
- 注意:每种模式都用于解决特定的问题域
1 创建型模式
1.1 工厂模式
-
功能:工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
-
分类
-
工厂模式在《Java与模式》中分为三类:
- 简单工厂模式(Simple Factory):不利于产生系列产品;
- 工厂方法模式(Factory Method):又称为多形性工厂;
- 抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;
这三种模式从上到下逐步抽象,并且更具一般性
-
GOF在《设计模式》一书中将工厂模式分为两类:
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
- 将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
-
工厂模式包括的角色
- 抽象产品类:所创建产品的父类,给出一个抽象接口或抽象类,以及一般由具体产品类具体实现。
- 具体产品类:抽象产品类的实现类,为实现某个具体产品的对象。
- 抽象工厂类:工厂模式的核心(简单工厂模式无此抽象类),是具体工厂必须实现的接口或者必须继承的父类。
- 具体工厂类:继承抽象工厂类,实现具体业务逻辑。
-
示例(后面程序用到的公共部分):果园员工种植水果(苹果,香蕉,葡萄)
abstract class Fruit{
private String name;
public Fruit() {
}
public Fruit(String name){
this.name = name;
}
public String toString(){
return "我是"+name;
}
}
class Apple extends Fruit{
public Apple(String name){
super(name);
}
public Apple() {
super("苹果");
}
}
class Banana extends Fruit{
public Banana(String name) {
super(name);
}
public Banana(){
super("香蕉");
}
}
1.1.1 简单工厂模式
- 概述
- 又称为静态工厂方法模式。
- 核心是一个具体的类
- 示例代码
//工厂类(核心)
public class FruitFactory {
public static final String APPLE ="apple";
public static final String BANANA ="banana";
public static Fruit getProduct(String type){
if(APPLE.equals(type)){
return new Apple();
}else if(BANANA.equals(type)){
return new Banana();
}
return null;
}
}
//客户端
public class client {
public static void main(String[] args) {
Fruit f = FruitFactory.getProduct(FruitFactory.APPLE);
System.out.println(f);
f = FruitFactory.getProduct(FruitFactory.BANANA);
System.out.println(f);
}
}
- 优点 & 缺点
- 优点:如果客户端需要某种产品,只需向工厂类发送请求,由该类负责所有产品的生产。
- 缺点:如果新增具体产品的时候,需要动到工厂类的代码,逻辑判断需要做改动。
1.1.2 工厂方法模式
- 概述
- 它是简单工厂模式的进一步抽象化和推广
- 工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。
- 核心是一个抽象工厂类
- 示例代码
//抽象工厂类
public abstract class FruitFactory {
public abstract Fruit getProduct();
}
//具体子类:苹果工厂
class AppleFactory extends FruitFactory{
@Override
public Fruit getProduct() {
return new Apple();
}
}
//具体子类:香蕉工厂
class BananaFactory extends FruitFactory{
@Override
public Fruit getProduct() {
return new Banana();
}
}
//客户端
public class client {
public static void main(String[] args) {
FruitFactory fc = new AppleFactory();
Fruit f = fc.getProduct();
System.out.println(f);
fc = new BananaFactory();
System.out.println(fc.getProduct());
}
}
- 优点 & 缺点
- 优点:
- 解决简单工厂模式有新产品加入时,需要更改原有工厂类的问题.本模式中,一旦有新产品加入,只需要创建与之对应的具体工厂类。
- 符合设计原则,降低了对象之间的耦合度。
- 缺点:
- 系统中存在大量的具体工厂类,且每个工厂类只负责一个子产品的生产,不符合现实世界问题域。
- 不能解决多维产品问题(比如不只生产水果,还生产蔬菜等。。。)
- 优点:
1.1.3 抽象工厂模式
- 概述
- 定义:为创建一组相关或者是相互依赖的对象提供的一个接口
- 产品族:不同产品类中功能相关联的产品组成的家族。(昆山基地:生产苹果和西红柿;上海基地:生产香蕉和土豆)。昆山基地和上海基地都是一个产品族。
- **工厂方法模式 & 抽象工厂模式 **
-
工厂方法模式
- 一个抽象产品类(Friut),可以派生出多个具体产品类(Apple,Banana等)
- 一个抽象工厂类(FruitFactory),可以派生出多个具体工厂类(AppleFactory,BananaFactory)。
- 每个具体工厂类只能创建一个具体产品类的实例(如AppleFactory只能创建Apple的实例)。
-
抽象工厂模式
- 多个抽象产品类(Friut,Vegetable),每个抽象产品类可以派生出多个具体产品类(如Fruit可以创建出Apple,Banana等)
- 一个抽象工厂类(AbstractFactory),可以派生出多个具体工厂类(KunShanFactory,ShaiHaiFactory)。
- 每个具体工厂类可以创建多个具体产品类的实例(如KunShanFactory可以创建Apple,Tomato的实例)。
- 示例代码:要生产的产品族(如水果,蔬菜)有多个,而且不仅在昆山种,还在上海种…
//第一种抽象产品类:Fruit
abstract class Fruit{}
//Fruit的具体产品类
class Apple extends Fruit{}
class Potato extends Fruit{}
//第二种抽象产品类:Vegetable
abstract class Vegetable{}
//Vegetable的具体产品类
class Tomato extends Vegetable{}
class Tomato extends Vegetable{}
//抽象工厂类(一个产品族的抽象)
public abstract class AbstractFactory {
public abstract Fruit getFruit();
public abstract Vegetable getVegetable();
}
//具体工厂类:KunShanFactory(昆山工厂种植苹果和西红柿)
class KunShanFactory extends AbstractFactory{
@Override
public Fruit getFruit() {
return new Apple();
}
@Override
public Vegetable getVegetable() {
return new Tomato();
}
}
//具体工厂类:ShaiHai(上海工厂种植香蕉和土豆)
class ShaiHaiFactory Factory extends AbstractFactory{
@Override
public Fruit getFruit() {
return new Banana();
}
@Override
public Vegetable getVegetable() {
return new Potato();
}
}
- 优点 & 缺点
- 优点
- 解决多维度产品的生产问题。(工厂模式针对的是一个产品等级结构,抽象工厂模式针对的是面向多个产品等级结构)
- 具有工厂方法模式(降低了对象之间的耦合度)的优点。
- 缺点
- 产品族的扩展十分费力。产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。
- 在具体工厂类的方法中,对于产品族里的产品,只能使用其中一个。(昆山基地只能种水果类中的苹果,不能种其他的)。
- 举例:这个也比较好理解。在一些场景中,很适用:如一款车(具体工厂类)中具有海尔空调(具体产品1)和国产发动机(具体产品2),而对于空调来说,同一款车子不可以搭载两种空调。
- 优点
1.2 单例模式
- 核心:确保一个类只能有一个实例,且该类自己创建自己供外部用户使用
- 两种单例模式
-
饿汉式单例类:单例类被加载时,其静态变量被初始化,同时私有构造器被调用。
public class Singleton { //以下两行任意选一行(两种方法) private static Singleton s = new Singleton(); //public final static Singleton s = new Singleton(); private Singleton(){} public static Singleton getSingleton(){ return s; } }
-
懒汉式单例类:单例类被加载时不会被实例化,等到有人请求实例的时候根据情况构建。(控制并发访问)
public class Singleton { private static Singleton s; private Singleton(){} synchronized public static Singleton getSingleton(){ if(s==null){ s = new Singleton(); } return s; } }
-
1.3 生成器模式(Builder)
- 概述
- 一个产品通常由多个零部件组成,构建过程比较复杂。将产品的实现细节和产品的表现相分离。
- 注意:是解耦"构建对象过程"(盖房子的过程)和"对象的部件"(房子由窗户、门、墙构成)
- 示例代码:盖房子
//房子的组件类:墙、窗户、门
class Wall{}
class Window{}
class Door{}
//房子类
class House{
private String Wall;
private String Window;
private String Door;
}
//抽象类:民工
abstract class Builder{
House house = new House(); //构建房子的组成部件
abstract buildWall();
abstract buildWindow();
abstract buildDoor();
House getHouse(){return house;};
}
//民工的实现类:盖草房的民工
class CaoBuilder extends Builder{
@Override
public void buildWall() {
}
@Override
public void buildWindow() {
}
@Override
public void buildDoor() {
}
}
//设计师:盖房子的过程
Designer{
Builder builder;
Public Designer(Builder builder){
this.builder = builder;
}
constructHouse(){
builder.buildWall();
builder.buildWindow();
builder.buildDoor();
}
}
Client{
Builder builder = new caoBuilder();
Designer designer = new Designer(builder);
public static void main(String[] args) {
designer.constructHouse();
builder.getHouse();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BSwg33e5-1573197074289)(E:/myYouDaoYun/imageFile/OOAD_Builder.png)]
2. 结构型模式
2.1 适配器模式
- 适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
- 示例(前提:两个适配器)
//A:香港充电器(只能充香港手机) B:内陆充电器(只能充内陆手机)
interface InterfaceA{ //适配器类
MethodA();
}
interface InterfaceB{ //适配器类
methodB();
}
- 示例代码:拿一部国产手机去香港,需要用香港的充电器,A代表香港的充电器,b相当于适配器(即在A上插入一个插头,这个插头可以让国产手机充电)
class C implements A{ //只能由A适配到B(单向适配)
InterfaceB b; //相当于适配器
methodA(){
b.methodB();
}
}
Class C implements A,B{ //双向适配
InterfaceB b;
InterfaceA a;
methodA(){
b.methodB();
}
methodB(){
a.methodA();
}
}
2.2 Façade模式(外观模式/门面模式)
- 概述
- Facade模式:为子系统中的一组接口提供一致的界面,Façade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用.
- A为了完成某项功能,需要和一系列的对象进行交互,这个时候可以提取出一个门面类,由门面类和那些对象进行交互,而让A与这个门面类进行交互(最少交互原则,迪米特法则)。
- 示例代码
/*Facade模式(门面模式):将所有的对象组合起来,一起启动和关闭
* 此程序中:Facade类将AlarmA和Monitor类关联起来,一起控制它们的启动和关闭
* */
//报警器类
class AlarmA{
private String name;
public AlarmA(String name) {
this.name = name;
}
public void turnOn(){
System.out.println(name+"报警器启动");
}
public void turnOff(){
System.out.println(name+"报警器关闭");
}
}
//监控器类
class Monitor{
private String name;
public Monitor(String name) {
this.name = name;
}
public void turnOn(){
System.out.println(name+"监控器启动");
}
public void turnOff(){
System.out.println(name+"监控器关闭");
}
}
//门面类
public class Facade {
private AlarmA a;
private Monitor b;
public Facade(AlarmA a,Monitor b) {
this.a = a;
this.b =b;
}
public void turnOn(){
a.turnOn();
b.turnOn();
}
public void turnOff(){
a.turnOff();
b.turnOff();
}
public static void main(String[] args) {
AlarmA a = new AlarmA("A");
Monitor b = new Monitor("B");
Facade f= new Facade(a,b);
f.turnOn(); //一起控制报警器和监控器的启动
System.out.println("---------");
f.turnOff(); //一起控制报警器和监控器的关闭
}
}
2.3 代理模式
- 概述:为其他对象提供一种代理以控制对这个对象的访问。
- 注意:代理需要有被代理的行为,而且要比被代理的更丰富,还需要有过滤功能。
- 示例:老板和秘书
3. 行为型模式
3.1 Command命令模式
- Command命令模式:对命令进行封装,把发出命令的职责和执行命令的职责分隔开.
- 角色可以分为:
- 请求者角色:负责调用命令对象
- 接受者角色:命令的接受者,负责具体实施命令。
- 命令角色
- 示例:我叫张三去买水
- 分析
- 请求者/发出者:我
- 接受者:张三
- 命令:买水
- 示例代码
//命令(抽象类) public interface Command { void execute(); } //具体命令 class BuyWater implements Command{ private Receiver receiver; public BuyWater(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { //命令关联执行者 receiver.action("去买水"); } } //请求者/发出者 class Invoker{ //发出者发送命令 public void send(Command command){ command.execute(); } } //接受者 class Receiver { private String name; public Receiver(String name) { this.name = name; } public void action(String msg){ System.out.println("我是"+name); System.out.println("我准备"+msg); } } //客户端 public class Client { public static void main(String[] args) { //命令 //命令的执行者 //命令的发出者 //李四让张三去买水 Receiver r = new Receiver("张三"); Command com = new BuyWater(r); Invoker in = new Invoker(); in.send(com); } }
- 分析
3.2 观察者模式(Observer)
-
概述:一个软件系统中包含了多个对象,对象之间彼此依赖和约束。通常一个对象的状态发生改变时,会引起其他的对象做出相应的改变.观察者模式就是其中一种方案,当被观察者在状态发生改变时,主动通知所有对他感兴趣的观察者对象,使观察者对象做出相应的改变。
-
观察者模式:定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象。这样一个主题对象在状态上的变化能够通知所有依赖于此对象的观察者对象,使这些观察者对象能够自动更新。
-
角色
- 被观察者:一个
- 观察者:多个
- 主题/事件:被观察者可以察觉到的事件,或被观察者的状态。
-
观察者模式的总结:一个被观察者对应多个观察者,当被观察者在状态发生改变时,主动通知所有对他感兴趣的观察者对象,使观察者对象做出相应的改变。
-
观察者模式的应用:事件监听处理机制
-
示例
- 题目:小明和弟弟对妈妈说:“妈妈,我们在院子里玩,饭做好了就叫我们一声”。请用观察者模式加以解释。
- 观察者:小明和弟弟
- 被观察者:妈妈
- 分析:”小明”和”弟弟”向系统的主题“妈妈”登记了一个感兴趣的事件(“饭熟了”),妈妈在事件发生时,通知所有对该事件感兴趣的观察者对象(也就是“小明”和“弟弟”),使他们改变原有行为采取相应的行为(“去吃饭”).
- 题目:小明和弟弟对妈妈说:“妈妈,我们在院子里玩,饭做好了就叫我们一声”。请用观察者模式加以解释。
-
示例代码
- 观察者
public interface Observer { //观察者:小明和弟弟
void listener(); //一直监听妈妈发来的通知
}
class ObserverInstance implements Observer{
private String name; //观察者的名字
public ObserverInstance(String name) {
this.name = name;
}
@Override
public void listener() {
System.out.println(name+"收到通知!");
}
}
- 被观察者:当主题(饭熟了)变化时,他主动通知对她感兴趣的观察者
public interface BeiObserver { //被观察者:妈妈
void addObserver(Observer observer);
void removeAllObsever();
void notifyAllObserver();
}
class BeiOberserInstance implements BeiObserver{
List<Observer> list = new ArrayList<Observer>();
public void setName(String name) { //设置饭的状态
notifyAllObserver();
}
@Override
public void addObserver(Observer observer) {
list.add(observer);
}
@Override
public void removeAllObsever() {
list.removeAll(list);
}
@Override
public void notifyAllObserver() {
for(Observer observer:list){
observer.listener();
}
}
}
- 客户端测试
public class Test {
public static void main(String[] args) {
Observer observer1 = new ObserverInstance("xiaoming");
Observer observer2 = new ObserverInstance("didi");
BeiOberserInstance beiobserver = new BeiOberserInstance();
beiobserver.addObserver(observer1);
beiobserver.addObserver(observer2);
beiobserver.setName("饭好啦~");
}
}
3.3 责任链模式
- 责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并连着这条链传递该请求,直到有一个对象处理它为止。
- 举例:网上对于一些敏感信息的过滤
SB ---> ** :) ---> O(∩_∩)O哈哈~
- 示例代码
- 法1(通过第一个节点一直往后)
public abstract class Filter {
protected Filter nextFilter;
public void setNextFilter(Filter nextfilter){
this.nextFilter = nextfilter;
}
public abstract String doFilter(String msg);
}
class HTMLFilter extends Filter{
@Override
public String doFilter(String msg) {
String msgnew = msg.replace("<", "[").replace(">", "]");
if(nextFilter!=null){
msgnew = nextFilter.doFilter(msgnew);
}
return msgnew;
}
}
class SensitiveFilter extends Filter{
@Override
public String doFilter(String msg) {
String msgnew = msg.replace("SB","**");
if(nextFilter!=null){
msgnew = nextFilter.doFilter(msgnew);
}
return msgnew;
}
}
//客户端
public class Client {
public static void main(String[] args) {
String msg = "SB,<script>---</script>";
Filter filter1 = new HTMLFilter();
Filter filter2 = new SensitiveFilter();
filter1.setNextFilter(filter2);
String result = filter1.doFilter(msg); //通过依赖第一个节点完成后续节点的过滤
System.out.println(result);
}
}
- 法2:使用FilterChain:将所有的Filter示例都加入FilterChain中
public interface Filter {
public String doFilter(String msg, FilterChain chain);
}
class FilterChain implements Filter { //责任链
LinkedList<Filter> list;
int index = 0;
private int i = 0;
public FilterChain() {
list = new LinkedList<Filter>();
}
public void addFilter(Filter filter){
list.add(filter);
}
@Override
public String doFilter(String msg, FilterChain chain) {
if(i==list.size()) return msg; //这是最后一个过滤器
Filter f = list.get(i); //取第几个过滤器
i++;
return f.doFilter(msg, chain);
}
}
class HTMLFilter implements Filter {
@Override
public String doFilter(String msg, FilterChain chain) {
String msgnew = msg.replace("<", "[").replace(">", "]");
msgnew = chain.doFilter(msgnew, chain);
return msgnew;
}
}
class SensitiveFilter implements Filter {
@Override
public String doFilter(String msg, FilterChain chain) {
String msgnew = msg.replace("SB", "**");
msgnew = chain.doFilter(msgnew, chain);
return msgnew;
}
}
//客户端
public class Client {
public static void main(String[] args) {
String msg = "SB,<script>----</script>";
Filter filter1 = new HTMLFilter();
Filter filter2 = new SensitiveFilter();
FilterChain chain = new FilterChain();
chain.addFilter(filter1);
chain.addFilter(filter2);
String result = chain.doFilter(msg, chain); //通过责任链来完成每个节点的过滤
System.out.println(result);
}
}
3.4 状态模式
- 状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。
设计模式精简版
- 创建型模式:解决对象的创建问题
- 工厂模式[简单工厂模式,工厂方法模式,抽象工厂模式]
- 单例模式[饿汉式单例模式,懒汉式单例模式]
- 生成器模式/Builder:将"构建对象的过程"和"对象的部件"分开
- 结构型模式:描述如何将类和对象结合在一起,构成更大的结构。
- 适配器模式:使原本由于接口不兼容而不能一起工作的那些类可以一起工作
- Facade模式/门面模式/外观模式:为子系统中的一组接口提供一致的界面
- 代理模式:为其他对象提供一种代理以控制对这个对象的访问。代理需要有被代理的行为,而且要比被代理的更丰富,还需要有过滤功能。
- 行为型模式:描述的是算法和对象间职责的分配
- Command命令模式:对命令进行封装,把发出命令的职责和执行命令的职责分隔开.
- 观察者模式:当被观察者在状态发生改变时,主动通知所有对他感兴趣的观察者对象,使观察者对象做出相应的改变。
- 责任链模式:将这些对象连成一条链,并连着这条链传递该请求,直到有一个对象处理它为止.从而避免请求的发送者和接受者之间的耦合关系.
- 状态模式:把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。