设计模式
六大原则
- 单一职责原则
就一个类而言,应该仅有一个引起它变化的原因。
例如,在 Activity 中不应该存在 Bean 文件、网络数据处理以及列表的 Adapter。 - 开放封闭原则
类、模块、函数等应该是可以扩展的,但是不可修改。
开放封闭原则有两个含义:一个是对于拓展是开放的,另一个是对于修改是封闭的。 - 里氏替换原则
所有引用基类(父类)的地方必须能够透明地使用其子类的对象。 - 依赖倒置原则
高层模块不应该依赖低层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。 - 迪米特原则
一个软件实体应当尽可能少地与其他实体发生相互作用。 - 接口隔离原则
一个类对另一个类的依赖应该建立在最小的接口上。
设计模式分类
GoF 提出的设计模式总共有 23 种,根据目的准则分类,分为三大类。
- 创建型设计模式,共 5 种:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。(创建对象)
- 结构型设计模式,共 7 种:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 (对象的组成)
- 行为型设计模式,共 11 种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。(对象的功能)
简单工厂模式
简单工厂模式属于创建型模式又叫做静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。
简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式结构图
- Factory:工厂类,简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
- IProduct:抽象产品类,简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
- Product:具体产品类,是简单工厂模式的创建目标。
这里我们用生产电脑来举例,假设有一个电脑的代工生产商,它目前已经可以代工生产联想电脑了,随着业务的拓展,这个代工生产商还要生产惠普和华硕的电脑,这样我们就需要用一个单独的类来专门生产电脑,这就用到了简单工厂模式。下面我们来实现简单工厂模式:
创建抽象产品类
我们创建一个电脑的抽象产品类,他有一个抽象方法用于启动电脑:
public abstract class Computer {
/**
* 产品的抽象方法,由具体的产品类去实现
*/
public abstract void start();
}
创建具体产品类
接着我们创建各个品牌的电脑,他们都继承了他们的父类Computer ,并实现了父类的start方法:
联想电脑:
public class LenovoComputer extends Computer{
@Override
public void start() {
System.out.println("联想电脑启动");
}
惠普电脑:
public class HpComputer extends Computer{
@Override
public void start() {
System.out.println("惠普电脑启动");
}
}
华硕电脑:
public class AsusComputer extends Computer {
@Override
public void start() {
System.out.println("华硕电脑启动");
}
}
创建工厂类
接下来创建一个工厂类,它提供了一个静态方法createComputer用来生产电脑。你只需要传入你想生产的电脑的品牌,它就会实例化相应品牌的电脑对象:
public class ComputerFactory {
private ComputerFactory();//别人不能随便创建对象
public static Computer createComputer(String type){
if("lv".equals(type)){
return new LenovoComputer();
}else if("hp".equals(type)){
return new HpComputer();
}else if("asus".equals(type)){
return new AsusComputer();
}else{
return null;
}
}
}
客户端调用工厂类
客户端调用工厂类,传入“hp”生产出惠普电脑并调用该电脑对象的start方法:
public class CreatComputer {
public static void main(String[]args){
Computer c1 = ComputerFactory.createComputer("hp");
if(c1 != null){
c1.start()
}else{
System.out.println("暂时没有")
}
}
}
优点和缺点
优点
- 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点
- 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
- 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,同样破坏了“开闭原则”;在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
- 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
适用环境
在以下情况下可以使用简单工厂模式:
- 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
模式应用
- JDK类库中广泛使用了简单工厂模式,如工具类java.text.DateFormat,它用于格式化一个本地日期或者时间。
public final static DateFormat getDateInstance();
public final static DateFormat getDateInstance(int style);
public final static DateFormat getDateInstance(int style,Locale locale);
- 获取不同加密算法的密钥生成器。
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
工厂方法模式
模式介绍
- 工厂方法模式是一种简单的模式,在平时开发中应用很广泛,也许你不知道但已经使用了无数次该模式了,如android中的activity里的各个生命周期方法,以onCreate为例,它就可以看作一个工厂方法。
我们在构造了一个ConstraintLayout布局里面有很多的子View,所有的视图最终都继承自View可以看作抽象产品,我们具体使用的View就是具体产品。我们使用的activity继承自Baseactivity,activity看作一个具体工厂,Baseactivity看作抽象工厂,通过其继承的onCreate方法最终创建布局,这就是工厂方法的含义。
**
定义与类型
- 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行
- 类型:创建型
使用场景
-
创建对象需要大量重复的代码
-
客户端不依赖于产品类实例如何被创建、实现的细节
-
一个类通过子类来制定创建哪个对象
优点
-
用户只需要关心所需产品的对应工厂,无需关心细节
-
加入新产品符合开闭原则,提高可扩展性
缺点
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
UML类图:
Factory_Method.png
工厂方法有4个对象:
抽象工厂类(Factory):提供抽象方法供具体工厂实现
具体工厂类(ConcreteFactory):提供具体的工厂
抽象产品类(Product):提供抽象方法供具体产品类实现
具体产品类(ConcreteProduct):提供具体的产品
使用步骤
步骤1: 创建抽象工厂类,定义具体工厂的公共接口;
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
步骤3: 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
**步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
- 抽象产品类:
public abstract class Video {
public abstract void produce();
}
- 具体产品类(ConcreteProduct)
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("Python课程视频");
}
}
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("Java课程视频");
}
}
- 抽象工厂类:
public abstract class VideoFactory {
public abstract Video getVideo();
}
- 具体工厂类:
public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
- 客户端调用:
public static void main(String[] args) {
VideoFactory vf = new PythonVideoFactory();
Video v = vf.getVideo();
v.produce();
}
简单工厂在源码中的使用–Collection:
- Collection(抽象工厂):
Iterator<E> iterator();
- ArrayList(具体工厂):
public Iterator<E> iterator() {
return new Itr();
}
- Iterator(抽象产品):
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
- Itr(具体产品):
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
'省略代码...'
}
单例模式
保证类在内存中只有一个对象。
1、把构造方法私有
2、在成员位置自己创建一个对象
3、公共方法提供访问
饿汉式 :类一加载就造对象
public class StudentDemo {
public static void main(String[] args) {
Student s1 = Student.getStudent();
Student s2 = Student.getStudent();
System.out.println(s1 == s2);//true
}
}
public class Student {
//构造私有
private Student() {
}
//不让外界修改
private static Student s = new Student();
//加静态保证外界访问
public static Student getStudent() {
return s;
}
}
懒汉式:用的时候才创建对象
public class TeacherDemo {
public static void main(String[] args) {
Teacher t1 = Teacher.getTeacher();
Teacher t2 = Teacher.getTeacher();
System.out.println(t1 == t2);//true
}
}
public class Teacher {
private Teacher() {
}
private static Teacher t = null;
//线程安全问题 要加同步
public synchronized static Teacher getTeacher() {
if(t == null) {
t = new Teacher();
}
return t;
}
}
体现:
Runtime类 饿汉式
调用dos命令