java设计模式

设计模式分类:

  • 创建形模式单例模式、抽象工厂模式、建造者模式工厂模式、原型模式
  • 结构型模式适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
  • 行为型模式模板方法模式、命令模式、迭代器模式、观察者模式、终结者模式、备忘录模式、解释器模式、状态模式、策略模式

 单例模式(Singleton Pattern):

该模式是Java中最简单的设计模式之一,属于创建形模型,提供了一种创建对象的最佳方式。这种模型涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

需要注意:

  • 单例类只能有一个实例
  • 单例类必须自己创建自己的唯一实例
  • 单例类必须给所有其他对象提供这一实例

优点:

  • 在内存里只有一个实例,减少内存的开销,尤其是频繁的创建和销毁实例
  • 避免对资源的多重占用(比如写文件操作) 

缺点:

  •  没有接口
  • 不能继承
  • 一个类应该只关心内部逻辑,而不关心外面怎么实例化,与单一职责原则冲突

具体一个实现方式: 

创建一个SingleObject

  1. 在该类中实例化一个该类的对象instance
  2. 添加一个私有化的构造方法,使得无法在该类外new一个对象
  3. 添加一个静态方法返回该类的实例对象instance。(仅通过类名调用该方法,获得instance这个对象,每次获取的对象都是同一个对象)
public class SingleObject {
	private static SingleObject instance = new SingleObject();
	//私有化的构造函数,这样该类就不会被实例化(无法new一个对象)
	private SingleObject() {
	}
	//获取唯一可用的对象
	public static SingleObject getInstance() {
		return instance;
	}
	//单例模式中的方法
	public void doit() {
		System.out.println("单例模式:成员方法");
	}
}

几种实现方式:懒汉式(在静态方法中初始化实例,以时间换空间);饿汉式(在声明对象的时就初始化,以空间换时间)

1、懒汉式:不支持多线程。

public class SingleObjectLazy {
	private static SingleObjectLazy instance;
	private SingleObjectLazy() {	
	}
	public static SingleObjectLazy getInstance() {
		if(instance == null) {
			instance = new SingleObjectLazy();
		}
		return instance;
	}
}

2、懒汉式:支持线程安全,第一次调用时初始化,避免内存浪费,通过synchronized修饰getInstance方法保证线程安全。

public class SingleObjectLazy {
	private static SingleObjectLazy instance;
	private SingleObjectLazy() {	
	}
	public static synchronized SingleObjectLazy getInstance() {
		if(instance == null) {
			instance = new SingleObjectLazy();
		}
		return instance;
	}
}

3、饿汉式:支持线程安全,不需要加锁,执行效率高,但是在类加载时就初始化,浪费内存。(比较常用的一种)

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

4、

5、

工厂模式(Factory Method):

该模式属于创建形模式,提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且通过使用一个共同的接口来指向新创建的对象。简言之:工厂就是负责生产产品的,在设计模式中,可以理解为负责生产对象的一个类,就是工厂类。

模式组成:

  • 抽象产品:具体产品的父类,所有的具体产品都要实现该接口或者继承该类
  • 具体产品:抽象产品的子类,就是工厂类要创建的目标类
  • 工厂:被外界调用,根据调用不同的方法产生不同的产品类的实例

 缺点:

  • 每增加一个产品,都需要增加一个具体来和对象实现工厂,使得系统中类的个数成倍增加,在一定成都上增加了系统的复杂度,同时也增加了系统具体类的依赖。

 注意事项:作为一种创建模式,在壬戌需要生成复杂对象的地方都可以使用工厂模式。复杂对象适合使用工厂模式,而简单对象(只需要通过new实例化的)无需使用工厂模式。如果使用工厂模式就需要引入一个工厂类,会增加系统的复杂度。

for example:一个工厂生产A、B、C、D类的商品。以工厂模式实现A、B、C、D这四款商品

步骤1:创建一个生产商品的抽象类,也可以是接口,并定义生产商品的抽象方法

public abstract class Product {
	public abstract void product();
}

步骤2:商品A、B、C分别继承Product类,并实现抽象方法

class ProductA extends Product{
	@Override
	public void product() {
		// TODO 自动生成的方法存根
		System.out.println("生产一个产品A");
	}
}
class ProductB extends Product{
	@Override
	public void product() {
		// TODO 自动生成的方法存根
		System.out.println("生产一个产品B");
	}
}
class ProductC extends Product{
	@Override
	public void product() {
		// TODO 自动生成的方法存根
		System.out.println("生产一个产品C");
	}
}

步骤3:创建一个工厂,通过创建静态方法从而根据传入不同参数创建不同具体产品的实例

public class Factory {
	public static Product Manufacture(String ProductName) {
		switch(ProductName) {
		case "A":
			return new ProductA();
		case "B":
			return new ProductB();
		case "C":
			return new ProductC();
		default:
			return null;	
		}
	}
}

优点:

  1. 将创造实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建
  2. 把初始化实例时的工作放到工厂里面,使得代码更容易维护。更符合面向对象的原则以及面向接口编程

缺点:

  1. 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会到影响
  2. 违背了“开放-关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂
  3. 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。

 工厂方法模式:

与简单工厂模式的不同在于:将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定该实例化哪一个类。实际上就是每一个都有其自己的子工厂,该子工厂继承工厂父类。

模式组成:

  • 抽象产品(Product):具体产品的父类,每个产品都继承这个类,并实现其中的方法
  • 具体产品:抽象产品的子类,描述生产的具体产品
  • 抽象工厂(Factory):具体工厂的父类,每个子工厂都继承该类,并添加其中的方法
  • 具体工厂:抽象工厂的子类,描述具体工厂的功能

例如:一个工厂只生产A产品,此时同时想生产B产品,要改变原工厂的配置比较困难,且要生产更多的产品就要一次一次的修改,因此通过办理分厂的方式来生产B产品

步骤1:工厂父类

public abstract class Factory {
	public abstract void factory();
}

步骤2:产品父类

public abstract class Product {
	public abstract void product();
}

步骤3:具体产品类,继承产品类,并实现其中的方法

class ProductA extends Product{
	@Override
	public void product() {
		System.out.println("生产一个A产品");
	}
}
class ProductB extends Product{
	@Override
	public void product() {
		System.out.println("生产一个B产品");
	}
}

步骤4:具体产品的子工厂继承工厂父类,并实现其中方法

class FactoryA extends Factory {
	@Override
	public Product factory() {
		return new ProductA();
	}

}
class FactoryB extends Factory {
	@Override
	public Product factory() {
		return new ProductB();
	}

}

步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例

public class Main {
	public static void main(String[] args) {
		//想要A产品
		Factory Factory = new FactoryA();
		Factory.factory().product();
		//又想要B产品
		Factory = new FactoryB();
		Factory.factory().product();
	}
}

//输出
生产一个A产品
生产一个B产品

优点:

  • 更符合开闭原则:新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可(简单工厂模式需要修改工厂类的判断逻辑)
  • 符合单一职责原则:每个具体子工厂类只负责创建对应的产品(简单工厂模式中的工厂类存在复杂的switch逻辑判读)
  • 没有使用静态工厂方法,可以形成基于继承的等级结构(简单工厂中的工厂类使用静态工厂方法,不能形成基于继承的等级结构)

缺点:

  • 在增加一个新的产品时候,除了要增加新产品类外,还要提供与之对应的具体工厂类,系统的类个数将会成对的增加,在一定程度上增加了系统的复杂度。同时,有更多类需要编译和运行,会给系统带来额外的开销
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行等译,增加了系统的抽象性和理解难度,且在实现时可能会需要用到DOM、反射等技术,增加了系统的实现难度。
  • 虽然保证了工厂方法内的对修改关闭,但是对于使用工厂方法的类,如果要更换另外一种产品,任然需要修改实例化的具体工厂
  • 一个具体工厂只能创建一种具体产品

 建造者模式:

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象,这种类型的设计模式数据创建型模式,提供了一种创建对象的最佳方式。一个Builder类会一步一步构造最终的对象,该Builder类是独立于其他对象的

一个实例帮助理解:一个套餐(汉堡,薯条,可乐)

主要作用:

  • 方便用户创建复杂的对象(不需要知道实现的过程)
  • 代码复用性&封装性(将对象构建过程的细节进行封装和复用)

模式:

  • 指挥者(Director)直接和客户(Client)进行需求沟通
  • 沟通后指挥者将客户创建产品的需要划分为各个部件的建造请求(Builder)
  • 将各个部件的建造者请求委派到具体的建造者(ConcreteBuilder)
  • 各个具体建造者负责进行产品部件的构建
  • 最终构建成具体的产品

搞个实例好理解:首先是人类,人是由头、手、脚、身体构成(假设就是这样)。因此先准备这些类:人,头,手,脚,身体,因为不同的人有不同的构造,因此零部件为抽象类

//人
public class People {
	private Head head;
	private Hand hand;
	private Foot foot;
	private Body body;
	public Head getHead() {
		return head;
	}
	public void setHead(Head head) {
		this.head = head;
	}
	public Hand getHand() {
		return hand;
	}
	public void setHand(Hand hand) {
		this.hand = hand;
	}
	public Foot getFoot() {
		return foot;
	}
	public void setFoot(Foot foot) {
		this.foot = foot;
	}
	public Body getBody() {
		return body;
	}
	public void setBody(Body body) {
		this.body = body;
	}
}
//头
public abstract class Head {
	public abstract void head();

}
//手
public abstract class Hand {
	public abstract void hand(); 
}
//脚
public abstract class Foot {
	public abstract void foot();
}
//身体
public abstract class Body {
	public abstract void body();
}


Builder类:创造不同类型的人的父类,抽象类

public abstract class Builder {
	public abstract void buildHead();
	public abstract void buildHand();
	public abstract void buildFoot();
	public abstract void buildBody();
	public abstract People buildPeople();
}

具体的Builder类:(假设是要创造一个巨人类)

public class HugeManBuilder extends Builder{
	private People people = new People();
	@Override
	public void buildHead() {
		// TODO 自动生成的方法存根
		people.setHead(new HugeHead());
	}
	@Override
	public void buildHand() {
		people.setHand(new HugeHand());
	}
	@Override
	public void buildFoot() {
		people.setFoot(new HugeFoot());
	}
	@Override
	public void buildBody() {
		people.setBody(new HugeBody());
	}
	@Override
	public People buildPeople() {
		return people;
	}
}

零部件的具体实现类:
public class HugeHead extends Head{
	@Override
	public void head() {
		System.out.println("生成一个巨大的头");
	}
}

public class HugeHand extends Hand{
	@Override
	public void hand() {
		System.out.println("生成一个巨大的手");
	}
}

public class HugeFoot extends Foot {
	@Override
	public void foot() {
		System.out.println("生成一个巨大的脚");
	}
}

public class HugeBody extends Body {
	@Override
	public void body() {
		System.out.println("生成一个巨大的身体");
	}
}

指挥者类:Director类,可以指定建造的顺序

public class Director {
	private Builder builder = null;
	public Director(Builder builder) {
		this.builder = builder;
	}
	public People construct() {
		builder.buildHead();
		builder.buildHand();
		builder.buildFoot();
		builder.buildBody();
		return builder.buildPeople();
	}
}

在外部,我想创建一个实例化一个巨人:

public class Main {
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Builder builder = new HugeManBuilder();
		Director director = new Director(builder);
		People hugeMan = director.construct();//调用construct方法,创建一个巨人
		show(hugeMan);
	}
	//显示巨人的信息
	public static void show(People people) {
		people.getHead().head();
		people.getHand().hand();
		people.getFoot().foot();
		people.getBody().body();
	}
}

//输出
生成一个巨大的头
生成一个巨大的手
生成一个巨大的脚
生成一个巨大的身体

上述例子是建造者模式的常规用法,Director类主要用于指导具体构建者如何构建产品,可以控制调用的先后次序,并向调用者返回完整的产品类。如果我还想创造小矮类,创建一个SmallManBuilder extends Builder,并实现其中的方法,同时要分别添加SmallHead extends Head、SmallHand extends Hand、SmallFoot extends Foot、SmallBody extends Body,并分别实现其中的抽象方法。在外部,将SmallManBuilder作为Director构造方法的传入参数类型。

优点:

  •  使用建造者模式可以使客户端不必知道产品内部组成的细节
  • 具体的建造者类之间是相互独立的,这有利于系统的扩展
  • 具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响

缺点:

  • 建造者模式所创建的产品一般具有较多的共同点,其余组成部分相似;如果产品之间的差异性很大,就不适合使用建造者模式,因此该模式的使用范围有一定的限制
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体的建造者类来实现这种变化,导致系统变得很庞大。

再总结一下:建造者模式,是将一个复杂的对象的构建与它的表示分离。先抽取一类事物的共性,例如人,都有胳膊有腿,那么这就是人的共性,而不同的人的胳膊腿有不同的形态,就需要分别实现。Builder类就是一个抽象的建造者,为一个人建造胳膊腿等。而不同的人就有不同的建造方式,那么就要继承Builder实现自己的建造方式。指挥者(Director)就将客户的需求划分为各个部件的建造请求,将各个部件的建造请求委派到具体的建造者,建造胳膊腿等,通过传入的具体建造者来确定建造什么样的。大概就是这个过程。

适配器模式:

 

 代理模式:

 

模板方法模式:

 

策略模式: 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值