Java设计模式
策略模式
- 声明一个接口用于描述要进行的操作
package com.hg.strategy;
public interface Operation {
public int doOperation(int num1, int num2);
}
- 声明一个类,调用接口的方法进行操作
package com.hg.strategy;
public class Caculator {
private Operation operation;
public void setOperation(Operation operation) {
this.operation = operation;
}
public int doOperation(int num1, int num2){
return this.operation.doOperation(num1, num2);
}
}
- 声明接口的实现类
package com.hg.strategy;
public class OperationAdd implements Operation{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
package com.hg.strategy;
public class OperationSub implements Operation{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
- 测试
package com.hg.strategy;
public class Test {
public static void main(String[] args) {
Caculator caculator = new Caculator();
Operation operation = new OperationAdd();
caculator.setOperation(operation);
System.out.println(caculator.doOperation(1, 2));
}
}
策略模式的好处是如果将接口生成一个jar包,引用这个jar包后,直接实现这个接口的方法就可以实现代码的扩展性,实现关闭修改,打开扩展的原则
装饰模式
装饰模式有两个重要的属性:装饰器,被装饰的对象,装饰器和被装饰的对象要实现同一个接口,装饰器中要使用被装饰的对象。
- 创建共同接口
package com.hg.decorator;
public interface Person {
public Double cost();
public void show();
}
- 创建被装饰对象,实现Person接口
package com.hg.decorator;
public class XiaoMing implements Person{
@Override
public Double cost() {
return 0.0;
}
@Override
public void show() {
System.out.println("没穿衣服的小明");
}
}
- 创建装饰器,实现Person接口
package com.hg.decorator;
public abstract class ClothingDecorator implements Person{
protected Person person;
public ClothingDecorator(Person person) {
this.person = person;
}
}
- 创建装饰器的子类,实现操作
package com.hg.decorator;
public class ShirtDecorator extends ClothingDecorator{
public ShirtDecorator(Person person) {
super(person);
}
@Override
public Double cost() {
return person.cost() + 1000;
}
@Override
public void show() {
this.person.show();
System.out.println("购买一件衬衫,花费:" + this.cost());
}
}
package com.hg.decorator;
public class TrouserDecorator extends ClothingDecorator{
public TrouserDecorator(Person person) {
super(person);
}
@Override
public Double cost() {
return this.person.cost() + 800;
}
@Override
public void show() {
System.out.println("购买了一条裤子,累计花费:" + this.cost());
}
}
- 测试类
package com.hg.decorator;
public class Test {
public static void main(String[] args) {
Person xiaoming = new XiaoMing();
xiaoming = new ShirtDecorator(xiaoming);
xiaoming.show();
System.out.println("共计花费:" + xiaoming.cost());
xiaoming = new TrouserDecorator(xiaoming);
xiaoming.show();
System.out.println("共计花费:" + xiaoming.cost());
}
}
xiaoming = new ShirtDecorator(xiaoming);
为什么ShirtDecorator
类的对象可以赋值给XiaoMing
类的对象,因为这两个类都实现了Person接口,所以可以互相赋值。
装饰模式通过扩充装饰器的子类,可以实现程序的扩展。
观察者模式
观察者模式定义了对象的一对多依赖关系,当“一”的状态发生改变,所有依赖也随之发生改变。观察者模式也称为发布模式。观察者模式有两个角色,观察者和被观察者,当被观察者模式发生改变时,观察者模式随之改变。具体实现方法为:被观察者保存一份观察者的列表,当被观察者状态改变时,会通知观察者进行更新。
观察者
package com.hg.observer;
//观察者
public abstract class Customer {
public abstract void update();
}
package com.hg.observer;
//观察者扩展类A
public class CustomerA extends Customer{
@Override
public void update() {
System.out.println("客户A报纸已送达");
}
}
package com.hg.observer;
//观察者扩展类B
public class CustomerB extends Customer{
@Override
public void update() {
System.out.println("客户B报纸已送达");
}
}
被观察者
package com.hg.observer;
import java.util.ArrayList;
import java.util.List;
//被观察者
public class NewsPaperOffice {
private List<Customer> customers = new ArrayList<>();
//将观察者添加到列表
public void addCustomers(Customer customer){
this.customers.add(customer);
}
//遍历所有观察者
public void notifyAllCustomers(){
for (Customer customer : this.customers) {
customer.update();
}
}
//状态改变,对观察者进行通知
public void newspaper(){
this.notifyAllCustomers();
}
}
测试程序
package com.hg.observer;
public class Test {
public static void main(String[] args) {
NewsPaperOffice newsPaperOffice = new NewsPaperOffice();
Customer customerA = new CustomerA();
Customer customerB = new CustomerB();
newsPaperOffice.addCustomers(customerA);
newsPaperOffice.addCustomers(customerB);
newsPaperOffice.newspaper();
}
}
单例模式
单线程下的单例模式
package com.hg.single;
public class Single {
private static Single instance;
private Single(){
System.out.println("创建了Single对象");
}
public static Single getInstance(){
if (instance == null) instance = new Single();
return instance;
}
}
package com.hg.single;
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 9; i++) {
Single single = Single.getInstance();
}
}
}
多线程下的单例模式
使用单线程模式下的单例模式开发,在多线程模式下,因各个线程抢占资源,所以导致getInstace()
方法还未进行判断就被多个线程调用,无法实现单例模式,需要给getInstace()
方法添加synchronized
关键字,给线程上锁。
package com.hg.single;
public class Single {
private static Single instance;
private Single(){
System.out.println("创建了Single对象");
}
public static synchronized Single getInstance(){
if (instance == null) instance = new Single();
return instance;
}
}
使用直接给方法加锁的方式会造成每个线程运行getInstace()
方法都会等待,造成资源浪费。
可以在声明instance时直接进行实例化,就不用加锁了。
package com.hg.single;
public class Single {
private static Single instance = new Single();
private Single(){
System.out.println("创建了Single对象");
}
public static Single getInstance(){
if (instance == null) instance = new Single();
return instance;
}
}
还可以进行双重检测,进行判断
package com.hg.single;
public class Single {
private volatile static Single instance;
private Single(){
System.out.println("创建了Single对象");
}
public static Single getInstance(){
if (instance == null){
synchronized (Single.class){
if (instance == null) instance = new Single();
}
}
return instance;
}
}
工厂模式
工厂模式在开发时不需要手动创建对象,创建对象的工作全部交由工厂类去完成,需要对象时,直接从工厂了调用相应的方法即可完成对象的创建。
创建接口
package com.hg.factory;
public interface Computer {
}
创建实现类
package com.hg.factory;
public class ComputerA implements Computer{
}
package com.hg.factory;
public class ComputerB implements Computer{
}
创建工厂类
package com.hg.factory;
public class ComputerFactory {
public Computer createComputer(String name){
Computer computer = null;
if (name == "a"){
computer = new ComputerA();
}
if (name == "b"){
computer = new ComputerB();
}
return computer;
}
}
测试类
package com.hg.factory;
public class Test {
public static void main(String[] args) {
ComputerFactory computerFactory = new ComputerFactory();
computerFactory.createComputer("a");
computerFactory.createComputer("b");
}
}
适配器模式
将一个接口转换为用户希望的另一个接口,解决类之间接口不兼容的问题,相当于电源的接口转换器,将两项插头转为三项插头。
创建一个播放类,播放不同格式的音乐文件
package com.hg.adapter;
public class MyPlayer {
public void playMp3(String filename){
System.out.println("play mp3:" + filename);
}
public void playWma(String filename){
System.out.println("play Wma" + filename);
}
}
创建一个播放器接口
package com.hg.adapter;
public interface MusicPlayer {
public void play(String type,String filename);
}
创建适配器,识别不同的音乐格式,播放音乐
package com.hg.adapter;
public class MusicAdapter implements MusicPlayer{
private MyPlayer myPlayer;
public MusicAdapter() {
this.myPlayer = new MyPlayer();
}
@Override
public void play(String type, String filename) {
if (type == "mp3") this.myPlayer.playMp3(filename);
if(type =="wma") this.myPlayer.playWma(filename);
}
}
测试
package com.hg.adapter;
public class Test {
public static void main(String[] args) {
MusicPlayer musicPlayer = new MusicAdapter();
musicPlayer.play("mp3","Break My Heart");
musicPlayer.play("wma","Bye Bye Bye");
}
}
代理模式
spring的aop就是通过代理模式来实现的,通过代理模式可以实现目标对象和业务方法的解耦合。
业务类要和代理类实现同一个接口
接口
package com.hg.proxy;
public interface House {
public void findHouse();
}
业务类(实现接口)
package com.hg.proxy;
public class XiaoMing implements House{
@Override
public void findHouse() {
System.out.println("找房子");
}
}
代理类(和业务类实现同一个接口)
package com.hg.proxy;
public class HouseProxy implements House{
private House house;
public HouseProxy(House house) {
this.house = house;
}
@Override
public void findHouse() {
//执行业务代码前,进行一些其他业务,如打印日志
System.out.println("日志:找了一个代理");
this.house.findHouse();
}
}
如何使用
package com.hg.proxy;
public class Test {
public static void main(String[] args) {
House house = new XiaoMing();
HouseProxy houseProxy = new HouseProxy(house);
houseProxy.findHouse();
}
}
模板方法模式
将不同类中相同的业务方法提取出来,封装到一个父类中的模式称为模板方法模式。子类可以将父类中的方法拿来直接使用,同时也可以修改继承的方法增加扩展业务。这种模式即保障了代码的复用性,又增加了代码的灵活性。
设计思路
已做饭为例子,开油烟机、生火、关火、关油烟机等操作是固定不变的,把这些操作放到一个模板类中
模板类
package com.hg.templatemethod;
public abstract class Cook {
public void open(){
System.out.println("打开油烟机");
}
public void fire(){
System.out.println("开火");
}
//不同的菜肴有不同的制作方法
public abstract void doCook();
public void outFire(){
System.out.println("关火");
}
public void close(){
System.out.println("关闭油烟机");
}
public void cook(){
open();
fire();
doCook();
outFire();
close();
}
}
炒西红柿类
package com.hg.templatemethod;
public class CookTomato extends Cook{
@Override
public void doCook() {
System.out.println("炒西红柿");
}
}
炒土豆类
package com.hg.templatemethod;
public class CookPotato extends Cook{
@Override
public void doCook() {
System.out.println("炒土豆丝");
}
}
测试类
package com.hg.templatemethod;
public class Test {
public static void main(String[] args) {
Cook cook = new CookTomato();
cook.cook();
System.out.println("******************************");
cook = new CookPotato();
cook.cook();
}
}
实践-模拟servlet的使用
Servlet
就是一种模板模式,我们可以模拟实现Servlet
继承关系来实践模板方法模式的开发
- 创建一个类实现
servlet
接口
package com.hg.templatemethod.servlet;
import javax.servlet.*;
import java.io.IOException;
public class MyGenericServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
其中需要操作的方法只有service方法,需要再实现一个类,将service方法单独提取出来
- 提取service方法,并根据不同的请求进行拆分
package com.hg.templatemethod.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyHttpServlet extends MyGenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
switch (request.getMethod()) {
case "GET":
doGet(request, response);
break;
case "POST":
doPost(request, response);
break;
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response) {
}
public void doPost(HttpServletRequest request, HttpServletResponse response) {
}
}
- 创建自己的
sevlet
package com.hg.templatemethod.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends MyHttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
}
}
责任链模式
是对请求的一种链式调用,所谓责任就是对请求的某些操作(如去除广告,游戏推广等)。具体实现是为某一个请求创建一个对象链,每个对象都会依次检查这个请求,并进行一些处理。
实践:模拟论坛对用户发的贴子进行过滤
信息对象
package com.hg.reponsibility;
//请求内容
public class Post {
//请求内容
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
处理器父类(每一个处理器都会包含链中的下一个处理器)
package com.hg.reponsibility;
public abstract class PostHandler {
//下一个处理器
private PostHandler handler;
public void setHandler(PostHandler handler) {
this.handler = handler;
}
//对请求的处理函数
public abstract void handlerRequest(Post post);
//将处理后的请求传递给下一个对象
public void next(Post post){
//如果有下一个处理器,就继续进行处理
if (this.handler != null){
this.handler.handlerRequest(post);
}else{
System.out.println("没有下一个处理器了");
}
}
}
处理器A
package com.hg.reponsibility;
public class AHandler extends PostHandler{
@Override
public void handlerRequest(Post post) {
//对post内容进行处理
String content = post.getContent();
content = content.replace("广告", "**");
post.setContent(content);
System.out.println("过滤广告");
//继续进行下一个处理
next(post);
}
}
处理器2
package com.hg.reponsibility;
public class BHandler extends PostHandler {
@Override
public void handlerRequest(Post post) {
String content = post.getContent();
content = content.replace("游戏推广", "****");
post.setContent(content);
System.out.println("过滤游戏推广");
next(post);
}
}
测试程序
package com.hg.reponsibility;
public class Test {
public static void main(String[] args) {
Post post = new Post();
post.setContent("正常内容,广告,游戏推广");
PostHandler postHandlerA = new AHandler();
PostHandler postHandlerB = new BHandler();
postHandlerA.setHandler(postHandlerB);
System.out.println("处理前的请求内容" + post.getContent());
postHandlerA.handlerRequest(post);
System.out.println("处理后的请求内容" + post.getContent());
}
}