java常用设计模式总结
1、工厂模式
作用:1、一些类的构造方法中的参数非常之多,传参容易出错、非常繁琐,维护也很麻烦
2、有时我们想要创建一个对象实现相应功能需要创建很多的对象,这时把创建对象的操作放在工厂中,由工厂代替我们来创建这些对象,避免重复造轮子。
例如:现在有很多的电子产品代工厂,不同的厂商都可以把自己的产品放在这个工厂中去建造,需要产品时,只需要向工厂中去拿,并告诉工厂你想要哪个品牌的产品即可,而不是每次都去找不同的品牌制造商去买。
1.1简单工厂
例如:想要买到不同品牌的耳机
1.1.1 创建耳机接口,并提供制造耳机的抽象方法:
public interface Headset {
void makeHeadSet();
}
1.1.2 小米和华为等不同品牌的耳机来继承耳机接口:
public class XiaoMiHeadset implements Headset {
@Override
public void makeHeadSet() {
System.out.println("工厂正在制造小米牌子的耳机");
System.out.println("成功获得小米牌子的耳机");
}
}
public class HuaWeiHeadset implements Headset {
@Override
public void makeHeadSet() {
System.out.println("工厂正在制造华为牌子的耳机");
System.out.println("成功获得华为牌子的耳机");
}
}
1.1.3 创建代工厂类,代工厂帮忙制造耳机:
public class ChinaFactory {
public ChinaFactory() {
}
//工厂中提供制造耳机的方法,参数为耳机的品牌,并返回耳机对象
public Headset makeHeadset(String brandName){
if (brandName==null){
return null;
}else if(brandName.equals("小米")){
return new XiaoMiHeadset();
}else if(brandName.equals("华为")){
return new HuaWeiHeadset();
}else {
return null;
}
}
}
1.1.4 创建测试类,从工厂中买到耳机
public class TestFactory {
public static void main(String[] args) {
BuyHeadset("小米");
}
/**
* 买耳机
* @param brandName 耳机品牌名
*/
static void BuyHeadset(String brandName){
ChinaFactory chinaFactory=new ChinaFactory();
Headset headset=chinaFactory.makeHeadset(brandName);
headset.makeHeadSet();
}
}
1.1.5 结果
1.2 工厂方法模式
在简单工厂模式种我们发现,这个工厂需要负责所有产品的代生产,工厂方法模式将生产不用品牌产品的工厂分给不同的工厂
耳机接口和不同耳机的实体类都不变
1.2.1 创建抽象工厂接口
public interface AbstractFactory {
Headset makeHeadset();
}
1.2.2 创建生产小米产品的工厂
public class XiaoMiFactory implements AbstractFactory {
@Override
public Headset makeHeadset() {
return new XiaoMiHeadset();
}
}
1.2.3 创建生产华为产品的工厂
public class HuaWeiFactory implements AbstractFactory {
@Override
public Headset makeHeadset() {
return new HuaWeiHeadset();
}
}
1.2.4 测试
public class TestFactory {
public static void main(String[] args) {
BuyHeadset();
}
/**
* 买耳机
*/
static void BuyHeadset(){
//只需直接找到华为的代工厂即可
AbstractFactory abstractFactory=new HuaWeiFactory();
Headset headset=abstractFactory.makeHeadset();
headset.makeHeadSet();
}
}
1.2.5 结果
1.3 抽象工厂模式
以上两种的工厂方式都是只针对一种产品的制造,小米和华为有很多的产品:手机、电脑、平板等等。。
我们只需继续编写实体类,并将响应产品的制造放入相应品牌的制造工厂中即可
现在新增手机的生产
1.3.1 产品接口和实体类
public interface PC {
void makePC();
}
public class XiaoMiPC implements PC {
@Override
public void makePC() {
System.out.println("小米电脑生产");
}
}
public class HuaWeiPC implements PC {
@Override
public void makePC() {
System.out.println("华为电脑生产");
}
}
1.3.2 在抽象工厂中添加PC的制造方法
public interface AbstractFactory {
Headset makeHeadset();
PC makePc();
}
public class HuaWeiFactory implements AbstractFactory {
@Override
public Headset makeHeadset() {
return new HuaWeiHeadset();
}
@Override
public PC makePc() {
return new HuaWeiPC();
}
}
public class XiaoMiFactory implements AbstractFactory {
@Override
public Headset makeHeadset() {
return new XiaoMiHeadset();
}
@Override
public PC makePc() {
return new XiaoMiPC();
}
}
1.3.3 测试
public class TestFactory {
public static void main(String[] args) {
System.out.println("生产耳机:");
BuyHeadset();
System.out.println("生产PC:");
BuyPC();
}
/**
* 买耳机
*/
static void BuyHeadset(){
AbstractFactory abstractFactory=new HuaWeiFactory();
Headset headset=abstractFactory.makeHeadset();
headset.makeHeadSet();
}
/**
* 买电脑
*/
public static void BuyPC(){
AbstractFactory abstractFactory=new XiaoMiFactory();
PC pc=abstractFactory.makePc();
pc.makePC();
}
}
1.3.4 结果
2、单例模式
单例模式即每个类只能有一个实例化的对象,可以避免某个频繁使用的类被频繁创建、销毁,节省资源消耗。
例如:每个班级只能有一个班主任,当校长、领导、教育局都想看某个老师的简历的时候,虽然每个人都拿到了一份简历(对象的引用),但是这几份简历都指向的是同一个老师(同一个对象)
单例模式的要求:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
2.1 饿汉式(类加载的时候直接创建对象)
容易产生垃圾对象,但执行效率比较高,多线程安全
public class Teacher {
private String name="张三";
private int age=18;
//类内部直接创建对象
private static Teacher teacher=new Teacher();
//私有无参构造方法
private Teacher(){}
public static Teacher getInstance(){
return teacher;
}
public String getName() {return name;}
public int getAge() { return age;}
public void setName(String name) {this.name = name;}
public void setAge(int age) {this.age = age;}
}
测试
public class Test {
public static void main(String[] args) {
//教育局来看老师的简历
Teacher teacher=Teacher.getInstance();
System.out.println("教育局看到老师的阿名字为:"+teacher.getName());
//现在校长来看老师的简历
Teacher teacher1=Teacher.getInstance();
System.out.println("校长看到的老师名字为:"+teacher1.getName());
}
}
结果
2.2 懒汉式(在调用getInstance()方法时才去创建对象)
public class Teacher {
private String name="张三";
private int age=18;
private static Teacher teacher;
private Teacher(){
}
//在这里加上synchronized关键字修饰成为线程安全的单例模式
/**
* public static synchronized Teacher getInstance(){
* if (teacher==null) {
* return teacher=new Teacher();
* }
* return teacher;
* }
*/
public static Teacher getInstance(){
if (teacher==null) {
return teacher=new Teacher();
}
return teacher;
}
public String getName() {return name;}
public int getAge() { return age;}
public void setName(String name) {this.name = name;}
public void setAge(int age) {this.age = age;}
}
3、建造者模式
对某些类的复杂构建,我们需要每次都去传入所有的参数,这样极大的降低的开发的效率,其实很多属性不需要特别的去关心。
例如:现在想要去建造一个房子,普通的住户是不知道房屋的每个墙具体有多高、多厚、多宽,只需要去关心想要什么类型的房子,比如说欧洲风格的,或者中国古典建筑。
3.1 实体类房子
public class House {
private String wallTypeName;
private String roofTypeName;
//构造方法传入建造者,并在内部实现复杂的构建过程
public House(HouseBuilder houseBuilder) {
this.roofTypeName=houseBuilder.getRoofType();
this.wallTypeName=houseBuilder.getWallType();
if("欧洲风格".equals(houseBuilder.getRoofType())){
System.out.println("欧洲风格的房顶开始建设");
System.out.println("复杂的房顶建造ing。。。");
}else if("中国古典".equals(houseBuilder.getRoofType())){
System.out.println("中国古典风格的房顶开始建设");
System.out.println("复杂的房顶建造ing。。。");
}
if("木头".equals(houseBuilder.getWallType())){
System.out.println("木头墙开始建造");
System.out.println("复杂的墙体建造ing。。。");
}else if("石头".equals(houseBuilder.getWallType())){
System.out.println("石头墙开始建造");
System.out.println("复杂的墙体建造ing。。。");
}
System.out.println("房子建成了");
}
public String getWallTypeName() {
return wallTypeName;
}
public void setWallTypeName(String wallTypeName) {
this.wallTypeName = wallTypeName;
}
public String getRoofTypeName() {
return roofTypeName;
}
public void setRoofTypeName(String roofTypeName) {
this.roofTypeName = roofTypeName;
}
}
3.2 建造者
public class HouseBuilder {
private String wallType;
private String roofType;
public House build(){
return new House(this);
}
public String getWallType() {return wallType;}
public void setWallType(String wallType) {this.wallType = wallType;}
public String getRoofType() {return roofType;}
public void setRoofType(String roofType) {this.roofType = roofType;}
@Override
public String toString() {
return "HouseBuilder{" +
"wallType='" + wallType + '\'' +
", roofType='" + roofType + '\'' +
'}';
}
}
3.3 测试
public class TestBuilder {
public static void main(String[] args) {
HouseBuilder houseBuilder=new HouseBuilder();
//用户需求为欧洲风格的石头墙的房子
houseBuilder.setRoofType("欧洲风格");
houseBuilder.setWallType("石头");
House house=houseBuilder.build();
System.out.println("房顶类型为:"+house.getRoofTypeName());
System.out.println("墙体类型为:"+house.getWallTypeName());
}
}
3.4 结果
ss TestBuilder {
public static void main(String[] args) {
HouseBuilder houseBuilder=new HouseBuilder();
//用户需求为欧洲风格的石头墙的房子
houseBuilder.setRoofType(“欧洲风格”);
houseBuilder.setWallType(“石头”);
House house=houseBuilder.build();
System.out.println(“房顶类型为:”+house.getRoofTypeName());
System.out.println(“墙体类型为:”+house.getWallTypeName());
}
}