简要描述
这些设计模式提供了一种方式:在创建对象的时候隐藏创建逻辑。(不是使用new运算符直接实例化对象)
带来的效果:使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
包括:工厂模式,抽象工厂模式,单例模式,建造者模式,原型模式。
设计模式的六大原则:
1、开闭原则:对扩展开发,对修改关闭。用到了接口和抽象类。
2、里氏代换原则:对实现抽象化(基类和子类的继承关系)的具体步骤的规范。
3、依赖倒转原则:针对接口编程,依赖于抽象而非具体。是开闭原则的基础。
4、接口隔离原则:使用多个隔离的接口,降低类间耦合度。
5、迪米特法则(最少知道原则):一个实体尽量少地和其他实体发生相互作用,使得系统功能模块相对独立。
6、合成复用原则:尽量使用合成/聚合,而不是使用继承。
一、工厂模式
介绍:
定义一个创建对象的接口,子类实现工厂接口(自己决定实例化哪一个工厂类)。
优点:
1、调用者创建对象时,只需要知道其名称;
2、扩展性高,增加一个产品只需要扩展一个工厂类;
3、屏蔽了具体实现,调用者只关心接口。
缺点:增加一个产品时,需要加一个具体类和对象实现工厂,使得类的个数成倍增加,从而增加了系统复杂度和系统具体类的依赖。
注:适用于复杂对象的生成。
使用时机:明确地计划不同条件下创建不同实例时。
实现:
以创建形状为例
步骤1:创建接口shape.java
public interface Shape {
/**
* 创建了一个接口
*/
void draw();
}
步骤2:创建实现接口的实体类RecTangle.java,Square.java,Circle.java
public class RecTangle implements Shape {
/**
* 创建接口的实现类Rectangle
*/
@Override
public void draw() {
// TODO 自动生成的方法存根
System.out.println("Rectangle");
}
}
public class Circle implements Shape {
/**
* 创建接口的实现类Circle
*/
@Override
public void draw() {
// TODO 自动生成的方法存根
System.out.println("Circle");
}
}
public class Square implements Shape {
/**
* 创建接口的实现类Square
*/
@Override
public void draw() {
// TODO 自动生成的方法存根
System.out.println("Square");
}
}
步骤3:创建工厂ShapeFactory.java
public class ShapeFactory {
/**
* 创建工厂,生成实体类的对象
* @param shapeType
* @return
*/
public Shape getShape(String shapeType) {
if(shapeType==null) {
return null;
}
if(shapeType.equals("R")) {
return new RecTangle();
}
if(shapeType.equals("S")) {
return new Square();
}
if(shapeType.equals("C")) {
return new Circle();
}
return null;
}
}
步骤4:使用工厂(通过传递类型信息获取实体类对象)
public class FactoryTest {
/**
* 测试
* 工厂类产生工厂对象
* 工厂对象调用工厂内方法来获取实体类对象
* @param args
*/
public static void main(String[] args) {
ShapeFactory shapeFactory=new ShapeFactory();
Shape s1=shapeFactory.getShape("C");
s1.draw();
Shape s2=shapeFactory.getShape("R");
s2.draw();
Shape s3=shapeFactory.getShape("S");
s3.draw();
}
}
二、抽象工厂模式
围绕一个超级工厂(其他工厂的工厂)创建其他工厂。
介绍:
抽象工厂包含许多具体工厂,每一个具体工厂里面有多种具体产品。
缺点:产品族扩展非常困难,要增加某个系列的某一产品,既要在抽象的Creator里面加代码,又要在具体的里面加代码。
使用时机:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
实现:
步骤1:为形状创建一个接口
package implement;
public interface Shape {
/**
* 创建了一个接口
*/
void draw();
}
步骤2:创建接口的实现类
package implementclass;
import implement.Shape;
public class RecTangle implements Shape {
/**
* 创建接口的实现类Rectangle
*/
@Override
public void draw() {
// TODO 自动生成的方法存根
System.out.println("Rectangle");
}
}
package implementclass;
import implement.Shape;
public class Square implements Shape {
/**
* 创建接口的实现类Square
*/
@Override
public void draw() {
// TODO 自动生成的方法存根
System.out.println("Square");
}
}
package implementclass;
import implement.Shape;
public class Circle implements Shape {
/**
* 创建接口的实现类Circle
*/
@Override
public void draw() {
// TODO 自动生成的方法存根
System.out.println("Circle");
}
}
步骤3:为颜色创建一个接口
package implement;
public interface Color {
void fill();
}
步骤4:创建接口的实现类
package implementclass;
import implement.Color;
public class Red implements Color {
@Override
public void fill() {
// TODO 自动生成的方法存根
System.out.println("红");
}
}
package implementclass;
import implement.Color;
public class Green implements Color {
@Override
public void fill() {
// TODO 自动生成的方法存根
System.out.println("绿");
}
}
package implementclass;
import implement.Color;
public class Blue implements Color{
@Override
public void fill() {
// TODO 自动生成的方法存根
System.out.println("蓝");
}
}
步骤5:为形状和颜色对象创建抽象类来获取工厂
package abstractfactory;
import implement.Color;
import implement.Shape;
public abstract class AbstractFactory {
public abstract Color getColor(String color);
public abstract Shape getShape(String shape);
}
步骤6:创建抽象类的工厂类
package factoryji;
import abstractfactory.AbstractFactory;
import implement.Color;
import implement.Shape;
import implementclass.Blue;
import implementclass.Green;
import implementclass.Red;
public class ColorFactory extends AbstractFactory{
@Override
public Color getColor(String color) {
// TODO 自动生成的方法存根
if(color==null) {
return null;
}
if(color.equalsIgnoreCase("h")) {
return new Red();
}
if(color.equalsIgnoreCase("g")) {
return new Green();
}
if(color.equalsIgnoreCase("b")) {
return new Blue();
}
return null;
}
@Override
public Shape getShape(String shape) {
// TODO 自动生成的方法存根
return null;
}
}
package factoryji;
import abstractfactory.AbstractFactory;
import implement.Color;
import implement.Shape;
import implementclass.Circle;
import implementclass.RecTangle;
import implementclass.Square;
public class ShapeFactory extends AbstractFactory {
/**
* 创建工厂,生成实体类的对象
* @param shapeType
* @return
*/
public Shape getShape(String shapeType) {
if(shapeType==null) {
return null;
}
if(shapeType.equals("r")) {
return new RecTangle();
}
if(shapeType.equals("s")) {
return new Square();
}
if(shapeType.equals("c")) {
return new Circle();
}
return null;
}
@Override
public Color getColor(String color) {
// TODO 自动生成的方法存根
return null;
}
}
步骤7:创建一个工厂生成器类
package vvcreatefactory;
import abstractfactory.AbstractFactory;
import factoryji.ColorFactory;
import factoryji.ShapeFactory;
public class FactoryProducer {
public static AbstractFactory getFactory(String choice) {
if(choice.equalsIgnoreCase("shape")) {
return new ShapeFactory();
}
if(choice.equalsIgnoreCase("color")) {
return new ColorFactory();
}
return null;
}
}
步骤8:测试使用
package abstractfactorytest;
import abstractfactory.AbstractFactory;
import createfactory.FactoryProducer;
import implement.Color;
import implement.Shape;
public class AbstractFactorytest {
public static void main(String[] args) {
AbstractFactory shapeFactory = FactoryProducer.getFactory("shape");
Shape shape1=shapeFactory.getShape("c");
Shape shape2=shapeFactory.getShape("r");
Shape shape3=shapeFactory.getShape("s");
shape1.draw();
shape2.draw();
shape3.draw();
AbstractFactory colorFactory=FactoryProducer.getFactory("color");
Color color1=colorFactory.getColor("h");
Color color2=colorFactory.getColor("b");
Color color3=colorFactory.getColor("g");
color1.fill();
color2.fill();
color3.fill();
}
}
三、单例模式
单例类只能有一个实例
单例类必须自己创建自己的唯一实例
单例类必须给所有其他对象提供这一实例
适用时机:控制实例数目,节省系统资源的时候。
优点:
1、减少了内存开销(尤其是频繁的创建和销毁实例)
2、避免对资源的多重占用
缺点:没有接口,不能继承
实现
步骤1:创建一个类
public class SingleObject {
private static SingleObject instance=new SingleObject();
private SingleObject() {
}
public static SingleObject getInstance() {
return instance;
}
public void showMessage() {
System.out.println("single");
}
}
步骤2:获取唯一对象
public class Singletest {
public static void main() {
SingleObject object=SingleObject.getInstance();
object.showMessage();
}
}
四、建造者模式
使用多个简单的对象一步一步构建成一个复杂的对象。一个Builder类会一步步构造最终对象,该Builder类独立于其他对象。
一个复杂对象由各个部分的子对象以一定算法构成,由于需求变化,复杂对象的各个部分经常发送剧烈变化,但组合在一起的算法相对稳定。
eg:JAVA中的SpringBuilder
优点:
1、易扩展
2、便于控制细节风险
缺点:
1、产品必须由共同点,范围有限
2、如内部变化复杂,会有很多的建造类
使用场景:
1、需要生成的对象具有复杂的内部结构。
2、需要生成的对象内部属性本身相互依赖。
与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
实现:
快餐店案例
步骤1:创建食物条目和食物包装的接口
package implement;
public interface Item {
public String name();
public Packing packing();
public float price();
}
package implement;
public interface Packing {
public String pack();
}
步骤2:创建实现包装接口的实体类
package implementpacking;
import implement.Packing;
public class Bottle implements Packing{
@Override
public String pack() {
// TODO 自动生成的方法存根
return "瓶子";
}
}
package implementpacking;
import implement.Packing;
public class Wrapper implements Packing{
public String pack() {
// TODO 自动生成的方法存根
return "纸袋子";
}
}
步骤3:创建实现食物条目接口的抽象类
package implementsitemabstract;
import implement.Item;
import implement.Packing;
import implementpacking.Wrapper;
public abstract class Burger implements Item{
public Packing packing() {
return new Wrapper();
}
public abstract float price();
}
package implementsitemabstract;
import implement.Item;
import implement.Packing;
import implementpacking.Bottle;
public abstract class ColdDrink implements Item{
public Packing packing() {
return new Bottle();
}
public abstract float price();
}
步骤4:创建扩展抽象类的实体类
package entityclass;
import implementsitemabstract.Burger;
public class BurgerChicken extends Burger {
@Override
public String name() {
// TODO 自动生成的方法存根
return "鸡肉汉堡";
}
@Override
public float price() {
// TODO 自动生成的方法存根
return 25.0f;
}
}
package entityclass;
import implementsitemabstract.Burger;
public class BurgerVeg extends Burger{
@Override
public String name() {
// TODO 自动生成的方法存根
return "蔬菜汉堡";
}
@Override
public float price() {
// TODO 自动生成的方法存根
return 15.0f;
}
}
package entityclass;
import implementsitemabstract.ColdDrink;
public class Doujiang extends ColdDrink{
@Override
public String name() {
// TODO 自动生成的方法存根
return "豆浆";
}
@Override
public float price() {
// TODO 自动生成的方法存根
return 9.0f;
}
}
package entityclass;
import implementsitemabstract.ColdDrink;
public class Coke extends ColdDrink {
@Override
public String name() {
// TODO 自动生成的方法存根
return "keke";
}
@Override
public float price() {
// TODO 自动生成的方法存根
return 9.0f;
}
}
步骤5:创建一个Meal类
package meallist;
import java.util.ArrayList;
import java.util.List;
import implement.Item;
public class Meal {
private List<Item> items=new ArrayList<>();
public void addItem(Item item) {
items.add(item);
}
public float pay() {
float all=0;
for(Item item:items) {
all+=item.price();
}
return all;
}
public void show() {
for(Item item:items) {
System.out.println("清单:"+item.name()+",打包方式"+item.packing().pack()+",总金额"+item.price());
}
}
}
步骤6:创建一个MealBuilder类,负责创建Meal
package mealbuilder;
import entityclass.BurgerChicken;
import entityclass.BurgerVeg;
import entityclass.Coke;
import entityclass.Doujiang;
import meallist.Meal;
public class MealBuilder {
//蔬菜汉堡+可口可乐
public Meal cookvac() {
Meal meal=new Meal();
meal.addItem(new BurgerVeg());
meal.addItem(new Coke());
return meal;
}
//肉汉堡+豆浆
public Meal cookcad() {
Meal meal=new Meal();
meal.addItem(new BurgerChicken());
meal.addItem(new Doujiang());
return meal;
}
}
步骤7:test
package test;
import mealbuilder.MealBuilder;
import meallist.Meal;
public class BuildTest {
public static void main(String[] args) {
MealBuilder mealBuilder=new MealBuilder();
Meal m1=mealBuilder.cookcad();
m1.show();
System.out.println("总价:"+m1.pay());
Meal m2=mealBuilder.cookvac();
m2.show();
System.out.println("总价:"+m2.pay());
}
}
五、原型模式
实现一个原型接口用于创建当前对象克隆。
使用场景:
1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。
4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
5、一个对象多个修改者的场景。
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。
注:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。
实现:
步骤1:创建一个实现Cloneable接口的实现类
package abstractimplement;
public abstract class Shape implements Cloneable{
private String id;
protected String type;
protected abstract void draw();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Object clone() {
Object clone=null;
try {
clone = super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
步骤2:创建扩展了上面抽象类的实体类。
package entityclass;
import abstractimplement.Shape;
public class Circle extends Shape {
public Circle() {
type="圆";
}
public void draw() {
// TODO 自动生成的方法存根
System.out.println("圆");
}
}
package entityclass;
import abstractimplement.Shape;
public class Rectangel extends Shape{
public Rectangel() {
type="三角";
}
public void draw() {
// TODO 自动生成的方法存根
System.out.println("三角");
}
}
package entityclass;
import abstractimplement.Shape;
public class Square extends Shape{
public Square() {
type="方";
}
public void draw() {
// TODO 自动生成的方法存根
System.out.println("方");
}
}
步骤3:创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。
package shapecache;
import java.util.Hashtable;
import abstractimplement.Shape;
import entityclass.Circle;
import entityclass.Rectangel;
import entityclass.Square;
public class ShapeCache {
private static Hashtable<String,Shape> shapeMap=new Hashtable<String,Shape>();
public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}
public static void loadCache() {
Circle circle = new Circle();
circle.setId("1");
shapeMap.put(circle.getId(),circle);
Square square = new Square();
square.setId("2");
shapeMap.put(square.getId(),square);
Rectangel rectangle = new Rectangel();
rectangle.setId("3");
shapeMap.put(rectangle.getId(),rectangle);
}
}
步骤 4:使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
package test;
import abstractimplement.Shape;
import shapecache.ShapeCache;
public class PrototypeTest {
public static void main(String[] args) {
ShapeCache.loadCache();
Shape clonedShape = (Shape) ShapeCache.getShape("1");
System.out.println("Shape : " + clonedShape.getType());
Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
System.out.println("Shape : " + clonedShape2.getType());
Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
System.out.println("Shape : " + clonedShape3.getType());
}
}