南宁码科网站建设,室内设计师优秀简介,开发公司网上申报,神点击恶意点击软件设计模式
前言
有一些重要的设计原则在开篇和大家分享下#xff0c;这些原则将贯通全文#xff1a; 面向接口编程#xff0c;而不是面向实现。这个很重要#xff0c;也是优雅的、可扩展的代码的第一步#xff0c;这就不需要多说了吧。 职责单一原则。每个类都应该只有一…设计模式
前言
有一些重要的设计原则在开篇和大家分享下这些原则将贯通全文 面向接口编程而不是面向实现。这个很重要也是优雅的、可扩展的代码的第一步这就不需要多说了吧。 职责单一原则。每个类都应该只有一个单一的功能并且该功能应该由这个类完全封装起来。 对修改关闭对扩展开放。对修改关闭是说我们辛辛苦苦加班写出来的代码该实现的功能和该修复的 bug 都完成了别人可不能说改就改对扩展开放就比较好理解了也就是说在我们写好的代码基础上很容易实现扩展。
创建型模式比较简单但是会比较没有意思结构型和行为型比较有意思
每个代理模式的代码都必须自己手动完成一遍。
创建型模式
创建型模式的作用就是创建对象说到创建一个对象最熟悉的就是 new 一个对象然后 set 相关属性。但是在很多场景下我们需要给客户端提供更加友好的创建对象的方式尤其是那种我们定义了类但是需要提供给其他开发者用的时候。
工厂模式分为简单工厂模式工厂模式抽象工厂模式
在工厂模式中我们在创建对象时不会对客户端暴露创建逻辑并且是通过使用一个共同的接口来指向新创建的对象。本质就是使用工厂方法代替new操作。
简单工厂模式
public class FoodFactory {public static Food makeFood(String name) {if (name.equals(兰州拉面)) {Food noodle new LanZhouNoodle();System.out.println(兰州拉面noodle出锅啦);return noodle;} else if (name.equals(黄焖鸡)) {Food chicken new HuangMenChicken();System.out.println(黄焖鸡 chicken 出锅啦);return chicken;} else {System.out.println(不知道你做的什么哦~);return null;}}
}其中LanZhouNoodle 和 HuangMenChicken 都继承自 Food。
public class Cook {public static void main(String[] args) {Food food FoodFactory.makeFood(黄焖鸡);FoodFactory.makeFood(jaja);}
}简单地说简单工厂模式通常就是这样一个工厂类 XxxFactory里面有一个静态方法根据我们不同的参数返回不同的派生自同一个父类或实现同一接口的实例对象。 我们强调职责单一原则一个类只提供一种功能FoodFactory 的功能就是只要负责生产各种 Food。 在此例中可以看出Cook 类在使用 FoodFactory 时就不需要 new 任何一个对象这就是简单工厂模式的好处封装了 new 的部分做到的代码易用性。
工厂模式
简单工厂模式很简单如果它能满足我们的需要我觉得就不要折腾了。之所以需要引入工厂模式是因为我们往往需要使用两个或两个以上的工厂。
public interface FoodFactory {Food makeFood(String name);
}
public class ChineseFoodFactory implements FoodFactory {Overridepublic Food makeFood(String name) {if (name.equals(A)) {return new ChineseFoodA();} else if (name.equals(B)) {return new ChineseFoodB();} else {return null;}}
}
public class AmericanFoodFactory implements FoodFactory {Overridepublic Food makeFood(String name) {if (name.equals(A)) {return new AmericanFoodA();} else if (name.equals(B)) {return new AmericanFoodB();} else {return null;}}
}其中ChineseFoodA、ChineseFoodB、AmericanFoodA、AmericanFoodB 都派生自 Food。
客户端调用
public class APP {public static void main(String[] args) {// 先选择一个具体的工厂FoodFactory factory new ChineseFoodFactory();// 由第一步的工厂产生具体的对象不同的工厂造出不一样的对象Food food factory.makeFood(A);}
}虽然都是调用 makeFood(“A”) 制作 A 类食物但是不同的工厂生产出来的完全不一样。
第一步我们需要选取合适的工厂然后第二步基本上和简单工厂一样。
核心在于我们需要在第一步选好我们需要的工厂。比如我们有 LogFactory 接口实现类有 FileLogFactory 和 KafkaLogFactory分别对应将日志写入文件和写入 Kafka 中显然我们客户端第一步就需要决定到底要实例化 FileLogFactory 还是 KafkaLogFactory这将决定之后的所有的操作。
抽象工厂模式
当涉及到产品族的时候就需要引入抽象工厂模式了。 一个经典的例子是造一台电脑 。
当涉及到这种产品族的问题的时候就需要抽象工厂模式来支持了。我们不再定义 CPU 工厂、主板工厂、硬盘工厂、显示屏工厂等等我们直接定义电脑工厂每个电脑工厂负责生产所有的设备这样能保证肯定不存在兼容问题。
当然抽象工厂的问题也是显而易见的比如我们要加个显示器就需要修改所有的工厂给所有的工厂都加上制造显示器的方法。这有点违反了对修改关闭对扩展开放这个设计原则。
本节要介绍的抽象工厂模式将考虑多等级产品的生产将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族图 1 所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tXbTibvX-1691644382209)(images/3-1Q1141559151S.gif)]
抽象工厂AbstractFactory模式的定义是一种为访问类提供一个创建一组相关或相互依赖对象的接口且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本工厂方法模式只生产一个等级的产品而抽象工厂模式可生产多个等级的产品。
使用抽象工厂模式一般要满足以下条件。
系统中有多个产品族每个具体工厂创建同一族但属于不同等级结构的产品。系统一次只可能消费其中某一族产品即同族的产品一起使用。
抽象工厂模式除了具有工厂方法模式的优点外其他主要优点如下。
可以在类的内部对产品族中相关联的多等级产品共同管理而不必专门引入多个新的类来进行管理。当增加一个新的产品族时不需要修改原代码满足开闭原则。
其缺点是当产品族中需要增加一个新的产品时所有的工厂类都需要进行修改。
单例模式
简单点说就是一个应用程序中某个类的实例对象只有一个你没有办法去new因为构造器是被private修饰的一般通过getInstance()的方法来获取它们的实例。
getInstance()的返回值是一个对象的引用并不是一个新的实例所以不要错误的理解成多个对象。
特点
类构造器私有持有自己类型的属性对外提供获取实例的静态方法
饿汉式写法
public class Singleton { private static Singleton instance new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; }
}弊端因为类加载的时候就会创建对象所以有的时候还不需要使用对象就会创建对象造成内存的浪费
饱汉模式最容易出错
public class Singleton {// 首先也是先堵死 new Singleton() 这条路private Singleton() {}// 和饿汉模式相比这边不需要先实例化出来注意这里的 volatile它是必须的private static volatile Singleton instance null;public static Singleton getInstance() {if (instance null) {// 加锁synchronized (Singleton.class) {// 这一次判断也是必须的不然会有并发问题if (instance null) {instance new Singleton();}}}return instance;}
}双重检查指的是两次检查 instance 是否为 null。 volatile 在这里是需要的希望能引起读者的关注。 很多人不知道怎么写直接就在 getInstance() 方法签名上加上 synchronized这就不多说了性能太差。 嵌套类最经典以后大家就用它吧
public class Singleton {private Singleton() {}// 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性private static class Holder {private static Singleton instance new Singleton();}public static Singleton getInstance() {return Holder.instance;}
}注意很多人都会把这个嵌套类说成是静态内部类严格地说内部类和嵌套类是不一样的它们能访问的外部类权限也是不一样的。 最后我们说一下枚举枚举很特殊它在类加载的时候会初始化里面的所有的实例而且 JVM 保证了它们不会再被实例化所以它天生就是单例的。
TODO:
建造者模式
原型模式
结构型模式
前面创建型模式介绍了创建对象的一些设计模式这节介绍的结构型模式旨在通过改变代码结构来达到解耦的目的使得我们的代码容易维护和扩展。
代理模式
第一个要介绍的代理模式是最常使用的模式之一了用一个代理来隐藏具体实现类的实现细节通常还用于在真实的实现的前后添加一部分逻辑。
既然说是代理那就要对客户端隐藏真实实现由代理来负责客户端的所有请求。当然代理只是个代理它不会完成实际的业务逻辑而是一层皮而已但是对于客户端来说它必须表现得就是客户端需要的真实实现。
理解代理这个词这个模式其实就简单了。 下面上代码理解。 代理接口
//要有一个代理接口让实现类和代理实现类来实现。
public interface FoodService {Food makeChicken();
}被代理的实现类
public class FoodServiceImpl implements FoodService {Overridepublic Food makeChicken() {Food f new Chicken();f.setChicken(1kg);f.setSpicy(1g);f.setSalt(3g);System.out.println(鸡肉加好佐料了);return f;}
}被代理实现类就只需要做自己该做的事情就好了不需要管别的。
代理实现类
public class FoodServiceProxy implements FoodService {// 内部一定要有一个真实的实现类当然也可以通过构造方法注入private FoodService foodService new FoodServiceImpl();Overridepublic Food makeChicken() {System.out.println(开始制作鸡肉);// 如果我们定义这句为核心代码的话那么核心代码是真实实现类做的// 代理只是在核心代码前后做些“无足轻重”的事情Food food foodService.makeChicken();System.out.println(鸡肉制作完成啦加点胡椒粉);food.addCondiment(pepper);System.out.println(上锅咯);return food;}
}客户端调用注意我们要用代理来实例化接口
// 这里用代理类来实例化
FoodService foodService new FoodServiceProxy();
foodService.makeChicken();所谓代理模式就是对被代理方法包装或者叫增强 在面向切面编程AOP中其实就是动态代理的过程。比如 Spring 中我们自己不定义代理类但是 Spring 会帮我们动态来定义代理然后把我们定义在 Before、After、Around 中的代码逻辑动态添加到代理中。
待续。。。
行为型模式
模板模式
在含有继承结构的代码中模板方法模式是非常常用的。
父类定义了骨架调用哪些方法及顺序某些特定方法由子类实现
模板方法只负责定义第一步应该要做什么第二步应该做什么第三步应该做什么至于怎么做由子类来实现。
好处代码复用减少重复代码。除了子类要实现的特定方法其他方法及方法调用顺序都在父类中预先写好
缺点 每一个不同的实现都需要一个子类来实现导致类个数增加使系统更加庞大
模板模式的关键点
1、使用抽象类定义模板类并在其中定义所有的基本方法、模板方法钩子方法不限数量以实现功能逻辑为主。其中基本方法使用final修饰其中要调用基本方法和钩子方法基本方法和钩子方法可以使用protected修饰表明可被子类修改。
2、定义实现抽象类的子类重写其中的模板方法甚至钩子方法完善具体的逻辑。
使用场景
1、在多个子类中拥有相同的方法而且逻辑相同时可以将这些方法抽出来放到一个模板抽象类中。
2、程序主框架相同细节不同的情况下也可以使用模板方法。
架构方法介绍
模板方法使得子类可以在不改变算法结构的情况下重新定义算法中的某些步骤。其主要分为两大类模版方法和基本方法而基本方法又分为抽象方法Abstract Method具体方法Concrete Method钩子方法Hook Method。
四种方法的基本定义前提在抽象类中定义
1抽象方法由抽象类声明由具体子类实现并以abstract关键字进行标识。
2具体方法由抽象类声明并且实现子类并不实现或者做覆盖操作。其实质就是普遍适用的方法不需要子类来实现。
3钩子方法由抽象类声明并且实现子类也可以选择加以扩展。通常抽象类会给出一个空的钩子方法也就是没有实现的扩展。它和具体方法在代码上没有区别不过是一种意识的区别而它和抽象方法有时候也是没有区别的就是在子类都需要将其实现的时候。而不同的是抽象方法必须实现而钩子方法可以不实现。也就是说钩子方法为你在实现某一个抽象类的时候提供了可选项相当于预先提供了一个默认配置。
4模板方法定义了一个方法其中定义了整个逻辑的基本骨架。
public abstract class AbstractTemplate {// 这就是模板方法public void templateMethod() {init();apply(); // 这个是重点end(); // 可以作为钩子方法}//这是具体方法protected void init() {System.out.println(init 抽象层已经实现子类也可以选择覆写);}// 这是抽象方法留给子类实现protected abstract void apply();//这是钩子方法可定义一个默认操作或者为空protected void end() {}
}