对于JAVA设计模式的自我修养
一 、工厂模式
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
1. 抽象工厂模式
抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
抽象工厂模式中,此例为A和B两家工厂,都生产小汽车和船,需要哪个工厂的船或者车子,在AFactoryThing 或者BFactoryThing中生产所需要的东西即可
类图
案例设计思路
- 创建一个工厂接口包含A和B工厂生产的方法,返回值为A中产品的父类,即满足无需指定它们具体的类。
- 创建A、B工厂并实现1中的接口 ,A中生产A产品,若A生产B则非法权限,B反之
- 创建A、B两工厂的自营店,分别继承AB工厂,实现AB工厂的规章制度,变量和方法
- 最后将写入自己工厂的产品类,继承自己的自营店。
代码案例
public interface AbstractCreateFactory {
AFactoryThing createAFactoryThing(int id);
BFactoryThing createBFactoryThing(int id);
}
public class AFactoryThing extends ProduceAFactory{
public int price = 0;
public String name = "A";
public void toProduce() {
System.out.println("这是我们A公司的" + name + "\t价格为" + price);
}
//从超市买东西,超市自己从商店买东西
}
public class BFactoryThing extends ProduceBFactory {
public int price = 0;
public String name = "B";
public void toProduce() {
System.out.println("这是我们B公司的" + name + "\t价格为" + price);
}
}
public class CarA extends AFactoryThing {
public CarA() {
price=9;
name="车子";
toProduce();
}
}
public class CarB extends BFactoryThing {
public CarB() {
name = "车子";
price = 10;
toProduce();
}
}
public class ProduceAFactory implements AbstractCreateFactory {
@Override
public AFactoryThing createAFactoryThing(int id) {
AFactoryThing aFactoryThing = null;
switch (id) {
case 0:
aFactoryThing = new CarA();
break;
case 1:
aFactoryThing = new ShipA();
break;
default:
aFactoryThing = new CarA();
break;
}
return aFactoryThing;
}
@Override
public BFactoryThing createBFactoryThing(int id) {
System.out.println("A工厂没有权限生产B产品");
return null;
}
}
public class ProduceBFactory implements AbstractCreateFactory {
@Override
public AFactoryThing createAFactoryThing(int id) {
System.out.println("B工厂没有权限生产A产品");
return null;
}
@Override
public BFactoryThing createBFactoryThing(int id) {
BFactoryThing bFactoryThing=null;
switch (id) {
case 0:
bFactoryThing=new CarB();
break;
case 1:
bFactoryThing=new ShipB();
break;
default:
bFactoryThing=new CarB();
break;
}
return bFactoryThing;
}
}
public class ShipA extends AFactoryThing {
public ShipA() {
price = 19;
name = "船";
toProduce();
}
}
public class ShipB extends BFactoryThing {
public ShipB() {
price = 20;
name = "船";
toProduce();
}
}
public class Client {
public static void main(String[] args) {
AFactoryThing aFactoryThing = new AFactoryThing();
BFactoryThing bFactoryThing = new BFactoryThing();
aFactoryThing.createAFactoryThing(0);
aFactoryThing.createAFactoryThing(1);
bFactoryThing.createBFactoryThing(0);
ShipB bFactoryThing1 = (ShipB)bFactoryThing.createBFactoryThing(1);
}
}
2. 简单工厂模式
类图
- 我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。
案例设计思路
简单工厂模式的创作思路就更简单了,工厂接口类,本例中用到了操作类工厂,返回自己需要的类型即可
代码案例
public interface AbstractCalculateFactory {
OperationCal createOperationCal(String message);
}
public class AddCalculate extends OperationCal {
public AddCalculate() {
message=add;
result = x + y;
showResult();
}
}
public class DivCalculate extends OperationCal {
public DivCalculate() {
message = div;
result = x / y;
showResult();
}
}
public class MulCalculate extends OperationCal{
public MulCalculate() {
message=mul;
result = x * y;
showResult();
}
}
public class ReduceCalculate extends OperationCal {
public ReduceCalculate() {
message = red;
result = x - y;
showResult();
}
}
public class OperationCal implements AbstractCalculateFactory {
public double x = 16;
public double y = 8;
public double result = 0;
public String message = "";
public static String add="ADD";
public static String red="RED";
public static String mul="MUL";
public static String div="DIV";
@Override
public OperationCal createOperationCal(String message) {
OperationCal operationCal = null;
switch (message) {
case "add":
operationCal = new AddCalculate();
break;
case "red":
operationCal = new ReduceCalculate();
break;
case "mul":
operationCal = new MulCalculate();
break;
case "div":
operationCal = new DivCalculate();
break;
default:
operationCal = new DivCalculate();
System.out.println("操作有误");
}
return operationCal;
}
public void showResult() {
System.out.println(x + message + y + "的结果为" + result + "\n");
}
}
public class OperationClient {
public static void main(String[] args) {
OperationCal operationCal=new OperationCal();
operationCal.createOperationCal("div");
operationCal.createOperationCal("mul");
operationCal.createOperationCal("add");
operationCal.createOperationCal("red");
}
}
二、建造者模式
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
类图
抽象类实现接口后 不用实现接口的所有方法 ,非抽象类就得实现接口的所有方法
普通类继承抽象类后,得重写实现抽象类未实现的方法!
案例设计思路
本实例中创建了Item(商品类目)和Packing(打包) 的接口,Item描述了name,packing和price方法,Packing描述了pack方法
实现接口 注意 Item(商品类目)包含Burger(汉堡)和ColdDrink(冷饮)两个抽象类 (注意为何写抽象类,抽象类中的price()方法可以忽略,那是一个抽象方法,不是实现Item中的price方法)所以抽象类只实现了packing方法,剩下两个方法在子类中实现的.(层层搭建)
瓶装和袋装两个类实现Packing接口,实体类封装搭建完毕之后开始管理类的搭建
做菜单管理类 meal ,添加商品(添加商品直接为item对象,不管是点什么菜品都加入其中即可),计算价钱,返回商品
最后MealBuilder 菜单建造者类 相当于客人点菜类,点好菜后,Meal 返回。
代码案例
package com.example.xm.build;
import java.util.ArrayList;
import java.util.List;
public interface Item {
public String name();
public Packing packing();
public float price();
}
interface Packing {
public String pack();
}
class Wrapper implements Packing {
@Override
public String pack() {
return "Wrapper";
}
}
class Bottle implements Packing {
@Override
public String pack() {
return "Bottle";
}
}
abstract class Burger implements Item {
@Override
public Packing packing() {
return new Wrapper();
}
@Override
public abstract float price();
}
abstract class ColdDrink implements Item {
@Override
public Packing packing() {
return new Bottle();
}
@Override
public abstract float price();
}
class VegBurger extends Burger {
@Override
public String name() {
return "Veg Burger";
}
@Override
public float price() {
return 0;
}
}
class ChickenBurger extends Burger {
@Override
public float price() {
return 50.5f;
}
@Override
public String name() {
return "Chicken Burger";
}
}
class Coke extends ColdDrink {
@Override
public float price() {
return 30.0f;
}
@Override
public String name() {
return "Coke";
}
}
class Pepsi extends ColdDrink {
@Override
public float price() {
return 35.0f;
}
@Override
public String name() {
return "Pepsi";
}
}
class Meal {
private List<Item> items = new ArrayList<Item>();
public void addItem(Item item){
items.add(item);
}
public float getCost(){
float cost = 0.0f;
for (Item item : items) {
cost += item.price();
}
return cost;
}
public void showItems(){
for (Item item : items) {
System.out.print("Item : "+item.name());
System.out.print(", Packing : "+item.packing().pack());
System.out.println(", Price : "+item.price());
}
}
}
class MealBuilder {
public Meal prepareVegMeal (){
Meal meal = new Meal();
meal.addItem(new VegBurger());
meal.addItem(new Coke());
return meal;
}
public Meal prepareNonVegMeal (){
Meal meal = new Meal();
meal.addItem(new ChickenBurger());
meal.addItem(new Pepsi());
return meal;
}
}
class BuilderPatternDemo {
public static void main(String[] args) {
MealBuilder mealBuilder = new MealBuilder();
Meal vegMeal = mealBuilder.prepareVegMeal();
System.out.println("Veg Meal");
vegMeal.showItems();
System.out.println("Total Cost: " +vegMeal.getCost());
Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
System.out.println("\n\nNon-Veg Meal");
nonVegMeal.showItems();
System.out.println("Total Cost: " +nonVegMeal.getCost());
}
}
三、原型模式
原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。(通过克隆返回对象)
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。(缓存对象,克隆返回对象)
类图
原型模式中设计思路 加载缓存返回缓存对象
案例设计思路
- 代码以加载图形和缓存为案例,创建三种图形类(相当于数据库的操作)
- 然后将图形加入到缓存中,ShapeCache 中的loadCache方法
- 其次再用getShape(id) 返回所需要的图形对象
原型模式的优点就是高性能,需要某个对象的时候能够快速的构建出来
另外 原型模式可逃避构造函数的约束。不需要new 的方式构建新对象
代码案例
public abstract class Shape implements Cloneable {
private String id;
protected String type="默认";
abstract void draw();
public String getType() {
return type;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
@Override
protected Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
public class Circle extends Shape {
public Circle() {
type = "圆";
}
@Override
void draw() {
System.out.println("画了一个" + type);
}
}
public class Rectangle extends Shape {
public Rectangle() {
type = "Rectangle";
}
@Override
void draw() {
System.out.println("画了一个"+type);
}
}
public class Square extends Shape {
public Square() {
type = "Square";
}
@Override
void draw() {
System.out.println("画了一个"+type);
}
}
public class ShapeCache { //形状缓存区
private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();
//读取形状
public static Shape getShape(String shapeId) {
Shape cache = shapeMap.get(shapeId);
return (Shape) cache.clone();
}
public static void loadCache() {
Circle circle = new Circle();
circle.setId("1");
Square square = new Square();
square.setId("2");
Rectangle rectangle = new Rectangle();
rectangle.setId("3");
shapeMap.put(circle.getId(), circle);
shapeMap.put(square.getId(), square);
shapeMap.put(rectangle.getId(), rectangle);
}
}
public class PrototypeClient {
public static void main(String[] args) {
ShapeCache.loadCache(); //加载缓存
Shape shape = ShapeCache.getShape("1");
shape.draw();
Shape shape1 = ShapeCache.getShape("2");
shape1.draw();
Shape shape2 = ShapeCache.getShape("3");
shape2.draw();
}
}
四、适配器模式
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。
适配器是什么,先从宏观上生活上,它就是一个用来适配某个东西来达到某种效果的一个物体,起到一个转换作用或者是红线作用
例子:本例子遵循菜鸟教程例子:有一个音频播放器,但是只支持mp3格式的播放,然后做了一个适配器,将音频播放器和适配器连接,播放mp4和vlc的音频,所以再音频播放器里直接调用适配器即可
类图
案例设计思路
- 适配器模式的代码对菜鸟做了略微的修改,修改后相对于原先更美观,更简洁
- 首先建立一个接口AdvanceMediaPlayer ,用mp4和vlc 两个类实现
- 然后建立一个适配器MediaAdapter,实现播放mp4和vlc为文件
- 最后将原始播放器拿过来继承适配器,这样原来的播放器就会支持本来的mp3和现有的mp4,vlc文件
- 最后Client 将需要的文件播放
代码案例
public interface AdvanceMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
public interface MediaPlayer {
void play(String audioTYpe,String fileName);
}
public class Mp4Player implements AdvanceMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("文件不匹配");
}
@Override
public void playMp4(String fileName) {
System.out.println("播放了Mp4" + fileName);
}
}
public class VlcPlayer implements AdvanceMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("播放了VLC"+fileName);
}
@Override
public void playMp4(String fileName) {
System.out.println("文件不匹配");
}
}
public class MediaAdapter implements MediaPlayer {
private AdvanceMediaPlayer advanceMediaPlayer;
public void prepareAudio(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advanceMediaPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advanceMediaPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advanceMediaPlayer.playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
advanceMediaPlayer.playMp4(fileName);
}
}
}
public class AudioPlay extends MediaAdapter{
public AudioPlay() {
}
@Override
public void play(String audioTYpe, String fileName) {
if (audioTYpe.equalsIgnoreCase("vlc") || audioTYpe.equalsIgnoreCase("mp4")) {
super.prepareAudio(audioTYpe);
super.play(audioTYpe, fileName);
} else if (audioTYpe.equalsIgnoreCase("mp3")) {
System.out.println("播放mp3");
} else {
System.out.println("不支持该文件");
}
}
}
public class AdapterClient {
public static void main(String[] args) {
AudioPlay audioPlayer = new AudioPlay();
audioPlayer.play("vlc","java.vlc");
audioPlayer.play("mp4","java.mp4");
audioPlayer.play("mp3","java.mp3");
audioPlayer.play("m","java.m");
}
}
五、桥接模式
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
类图
案例设计思路
- 桥接模式抽象类调用接口,实现代码独立通过抽象类来聚合接口,调用抽象类的子类,完成程序
- 定义好DrawApi 接口类,并用绿圆和红圆实现接口
- 再定义图形Shape类,聚合接口类,构造传参数,并抽象一个draw的方法
- 最后定义Circle类,继承Shape,实现draw方法,该方法里聚合接口类的方法,完成桥接模式。
代码案例
interface DrawApi {
void drawCircle();
}
public class RedCircle implements DrawApi{
@Override
public void drawCircle() {
System.out.println("画了一个红色的圆");
}
}
public class GreenCircle implements DrawApi{
@Override
public void drawCircle() {
System.out.println("画了一个绿色的圆");
}
}
public abstract class Shape {
public DrawApi drawApi;
public Shape(DrawApi drawApi) {
this.drawApi = drawApi;
}
abstract void draw();
}
public class Circle extends Shape {
public Circle(DrawApi drawApi) {
super(drawApi);
}
@Override
void draw() {
drawApi.drawCircle();
}
}
public class BridgeClient {
public static void main(String[] args) {
RedCircle redCircle = new RedCircle();
GreenCircle greenCircle = new GreenCircle();
Shape circle = new Circle(redCircle);
Shape circle1 = new Circle(greenCircle);
circle.draw();
circle1.draw();
}
}
六、单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。1.
懒汉式,线程不安全
public class LazySingle {
private static LazySingle lazySingle;
//调用实例方法时候再判断是否存在实例对象,线程不安全,操作不规范可能创建多个对象
public static LazySingle getInstance() {
if (lazySingle == null) {
lazySingle = new LazySingle();
}
return lazySingle;
}
}
懒汉式,线程安全
public class LazySingleSafe {
private static LazySingleSafe lazySingleSafe;
public static synchronized LazySingleSafe getInstance() {
//调用实例方法时候再判断是否存在实例对象,只不过方法加了个线程锁,防止多个线程同时进入
if (lazySingleSafe == null) {
lazySingleSafe = new LazySingleSafe();
}
return lazySingleSafe;
}
}
饿汉式
public class HungrySingle {
private static HungrySingle hungrySingle = new HungrySingle();
//先加载创建好对象后,调用实例方法直接返回静态对象
public static HungrySingle getInstance() {
return hungrySingle;
}
}
双检锁/双重校验锁
public class DoubleCheckSingle {
private static DoubleCheckSingle doubleCheckSingle;
//内部类 利用类加载器机制,进行同步锁,指挥加载一次,不会同时进入线程锁里面
public DoubleCheckSingle getInstances() {
if (doubleCheckSingle == null) {
synchronized (DoubleCheckSingle.class) {
if (doubleCheckSingle == null) {
doubleCheckSingle = new DoubleCheckSingle();
}
}
}
return doubleCheckSingle;
}
}
登记式/静态内部类
//内部类方式的单例模式
public class StaticSingle {
private static class StaticSingleHolder {
private static StaticSingle single = new StaticSingle();
}
//这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,
// 应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,
// 双检锁方式可在实例域需要延迟初始化时使用。
public StaticSingle getInstance() {
return StaticSingleHolder.single;
}
}
枚举
public enum EchoSingle {
INSTANCE;
}
//枚举机制的单例
class Client {
public static void main(String[] args) {
EchoSingle echoSingle = EchoSingle.INSTANCE;
}
}