在编写软件过程中,面临着来自耦合性,内举行以及可维护性,可扩展性,重用性,灵活性等多方面的问题,而设计模式就是来解决这些问题的,使程序具有更好的:
设计模式原则其实就是在编写的时候应当遵守的原则,也就是各种设计模式的基础(即设计模式为什么这样设计的依据)
理解:一个类只负责一项职责,提高类的可读性、可维护性。
实例:以交通工具为例
package cn.zhku;
public class SingleResponsibility1 {
public static void main(String[] args) {
RoadVehicle roadVehicle = new RoadVehicle();
AirVehicle airVehicle = new AirVehicle();
WaterVehicle waterVehicle = new WaterVehicle();
roadVehicle.run("摩托车");
airVehicle.run("飞机");
waterVehicle.run("船");
}
}
//遵守了单一职责原则,但是这样做的改动很大,要将类分解,而且还要修改客户端代码
//改进:直接修改Vehicle类,改动的代码会比较少
class RoadVehicle{
public void run(String vehicle){
System.out.println(vehicle+"在公路上运行");
}
}
class AirVehicle{
public void run(String vehicle){
System.out.println(vehicle+"在空中上运行");
}
}
class WaterVehicle{
public void run(String vehicle){
System.out.println(vehicle+"在水上运行");
}
}
package cn.zhku;
public class SingleResponsibility2 {
public static void main(String[] args) {
Vehicle2 vehicle2 = new Vehicle2();
vehicle2.run("汽车");
vehicle2.runAir("飞机");
vehicle2.runWater("轮船");
}
}
/**
* 第二种方式:
* 这种修改方法没有对原来的类做大的修改,只是增加了方法
* 这里虽然没有在类这个级别上遵守单一职责原则,但是在方法这个级别上任然遵守了单一原则
*/
class Vehicle2{
public void run(String vehicle){
System.out.println(vehicle+"在公路上运行");
}
public void runAir(String vehicle){
System.out.println(vehicle+"在天空运行");
}
public void runWater(String vehicle){
System.out.println(vehicle+"在水中运行");
}
}
理解:客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。
实例:有一个接口,里面含有5个方法,要求A类通过接口依赖B类,但是只用到1,2,3方法;C类通过接口依赖D,但是只用到1,4,5方法。
原始版本:
package cn.zhku;
//要求A类通过接口依赖B,但是只用到1,2,3方法
//C类通过接口依赖D,但是只用到1,4,5方法,明显这里的接口不满足接口隔离原则
public class Segregation1 {
public static void main(String[] args) {
}
}
interface Interface1{
void operation1();
void operation2();
void operation3();
void operation4();
void operation5();
}
class B implements Interface1{
@Override
public void operation1() {
System.out.println("B中实现了operation1");
}
@Override
public void operation2() {
System.out.println("B中实现了operation2");
}
@Override
public void operation3() {
System.out.println("B中实现了operation3");
}
@Override
public void operation4() {
System.out.println("B中实现了operation4");
}
@Override
public void operation5() {
System.out.println("B中实现了operation5");
}
}
class D implements Interface1{
@Override
public void operation1() {
System.out.println("D中实现了operation1");
}
@Override
public void operation2() {
System.out.println("D中实现了operation2");
}
@Override
public void operation3() {
System.out.println("D中实现了operation3");
}
@Override
public void operation4() {
System.out.println("D中实现了operation4");
}
@Override
public void operation5() {
System.out.println("D中实现了operation5");
}
}
class A{//A类通过接口Interface1依赖使用B类,但是只会用到1,2,3方法
public void depend1(Interface1 i){
i.operation1();
}
public void depend2(Interface1 i){
i.operation2();
}public void depend3(Interface1 i){
i.operation3();
}
}
class C {//A类通过接口Interface1依赖使用B类,但是只会用到1,2,3方法
public void depend1(Interface1 i) {
i.operation1();
}
public void depend4(Interface1 i) {
i.operation4();
}
public void depend5(Interface1 i) {
i.operation5();
}
}
问题所在:接口中有5个方法,但是A类在使用B的时候只用到了其中的三个方法,所以会导致接口过剩的情况。
解决:将接口拆分成三个接口
package cn.zhku;
public class Segregation2 {
public static void main(String[] args) {
A1 a1 = new A1();
a1.depend1(new B1());//A1类通过接口依赖B1类
a1.depend2(new B1());
a1.depend3(new B1());
C1 c1 = new C1();
c1.depend1(new D1());
c1.depend4(new D1());
c1.depend5(new D1());
}
}
interface InterfaceA{
void operation1();
}
interface InterfaceB{
void operation2();
void operation3();
}
interface InterfaceC{
void operation4();
void operation5();
}
class B1 implements InterfaceA,InterfaceB{
@Override
public void operation1() {
System.out.println("B中实现了operation1");
}
@Override
public void operation2() {
System.out.println("B中实现了operation2");
}
@Override
public void operation3() {
System.out.println("B中实现了operation3");
}
}
class D1 implements InterfaceA,InterfaceC{
@Override
public void operation1() {
System.out.println("D中实现了operation1");
}
@Override
public void operation4() {
System.out.println("D中实现了operation4");
}
@Override
public void operation5() {
System.out.println("D中实现了operation5");
}
}
class A1{//A类通过接口Interface1依赖使用B类,但是只会用到1,2,3方法
public void depend1(InterfaceA i){
i.operation1();
}
public void depend2(InterfaceB i){
i.operation2();
}
public void depend3(InterfaceB i){
i.operation3();
}
}
class C1 {//A类通过接口Interface1依赖使用B类,但是只会用到1,2,3方法
public void depend1(InterfaceA i) {
i.operation1();
}
public void depend4(InterfaceC i) {
i.operation4();
}
public void depend5(InterfaceC i) {
i.operation5();
}
}
理解:高层模块不应该依赖底层模块,二者都应该依赖器抽象(接口或抽象类)
中心思想:面向接口编程
案例:完成Person接收消息的功能
package cn.zhku;
public class DependencyInversion {
public static void main(String[] args) {
}
}
class Email{
public String getInfo(){
return "电子邮件信息:hello";
}
}
//完成Person接收消息的功能
//方式1
//分析:如果获取的对象是别的,比如微信,则新增类,同时Person也要新增相应的接收方法
//解决:引入一个抽象的接口IReceiver表示接受者,这样Person与这个接口发生依赖
//因为Email,WeiXin等等都属于接受者的范围,它们各自实现IReceiver接口就行了,这样就符合依赖倒转原则
class Person{
public void receive(Email email){
System.out.println(email.getInfo());
}
}
interface IReceiver{
}
解决:
package cn.zhku.improve;
public class DependencyInversion {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
person.receive(new WeiXin());
}
}
class Email implements IReceiver{
@Override
public String getInfo(){
return "Email电子邮件信息:hello";
}
}
class WeiXin implements IReceiver{
@Override
public String getInfo() {
return "微信电子邮件信息:hello";
}
}
//完成Person接收消息的功能
//定义接口
interface IReceiver{
public String getInfo();
}
//方式二
class Person{
public void receive(IReceiver receiver){
System.out.println(receiver.getInfo());
}
}
注意:低层模块尽量都要有抽象类或接口,程序稳定性会更好;变量的声明类型尽量是抽象类或接口,这样变量的引用和实际对象间就存在一个缓冲层,有利于程序扩展和优化。
理解:继承实际上让两个类的耦合性增强了,在适当的情况下可以通过聚合,组合,依赖来解决问题,在子类中尽量不要重写父类的方法。
案例:
package cn.zhku;
public class Liskov {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a = new A();
System.out.println("11-3=" + a.func1(11, 3));
System.out.println("1-8=" + a.func1(1, 8));
System.out.println("-----------------------");
B b = new B();
System.out.println("11-3=" + b.func1(11, 3));//这里本意是求出11-3,但是func1被重写了,所以结果不符合
System.out.println("1-8=" + b.func1(1, 8));// 1-8
System.out.println("11+3+9=" + b.func2(11, 3));
}
}
// A类
class A {
// 返回两个数的差
public int func1(int num1, int num2) {
return num1 - num2;
}
}
// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends A {
//这里,重写了A类的方法, 可能是无意识
public int func1(int a, int b) {
return a + b;
}
public int func2(int a, int b) {
return func1(a, b) + 9;
}
}
问题:B类继承了A类,但是B类无意中重写了A类的方法,所以在后面调用B类的方法时结果会与原本不符合。
解决:让原来的父类和子类都继承于一个更通俗的父类,原有的继承关系去掉。
package cn.zhku.improve;
public class Liskov {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a = new A();
System.out.println("11-3=" + a.func1(11, 3));
System.out.println("1-8=" + a.func1(1, 8));
System.out.println("-----------------------");
B b = new B();
//因为B类不再继承A类,因此调用者,不会再func1是求减法
//调用完成的功能就会很明确
System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出11+3
System.out.println("1+8=" + b.func1(1, 8));// 1+8
System.out.println("11+3+9=" + b.func2(11, 3));
//使用组合仍然可以使用到A类相关方法
System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3
}
}
//创建一个更加基础的基类
class Base {
//把更加基础的方法和成员写到Base类
}
// A类
class A extends Base {
// 返回两个数的差
public int func1(int num1, int num2) {
return num1 - num2;
}
}
// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends Base {
//如果B需要使用A类的方法,使用组合关系
private A Aa = new A();
//这里,重写了A类的方法, 可能是无意识
public int func1(int a, int b) {
return a + b;
}
public int func2(int a, int b) {
return func1(a, b) + 9;
}
//我们仍然想使用A的方法
public int func3(int a, int b) {
return this.Aa.func1(a, b);
}
}
理解:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
实例:
package cn.zhku;
public class Ocp {
public static void main(String[] args) {
//使用看看存在的问题
GraphicEditor graphicEditor = new GraphicEditor();
graphicEditor.drawShape(new Rectangle());
graphicEditor.drawShape(new Circle());
graphicEditor.drawShape(new Triangle());
}
}
//这是一个用于绘图的类 [使用方]
class GraphicEditor {
//接收Shape对象,然后根据type,来绘制不同的图形
public void drawShape(Shape s) {
if (s.m_type == 1)
drawRectangle(s);
else if (s.m_type == 2)
drawCircle(s);
else if (s.m_type == 3)
drawTriangle(s);
}
//绘制矩形
public void drawRectangle(Shape r) {
System.out.println(" 绘制矩形 ");
}
//绘制圆形
public void drawCircle(Shape r) {
System.out.println(" 绘制圆形 ");
}
//绘制三角形
public void drawTriangle(Shape r) {
System.out.println(" 绘制三角形 ");
}
}
//Shape类,基类
class Shape {
int m_type;
}
class Rectangle extends Shape {
Rectangle() {
super.m_type = 1;
}
}
class Circle extends Shape {
Circle() {
super.m_type = 2;
}
}
//新增画三角形
class Triangle extends Shape {
Triangle() {
super.m_type = 3;
}
}
问题分析:在新增一个画图功能的时候,需要在GraphicEditor类中作else if判断,没有遵循开闭原则,代码在管理起来变得复杂。
解决:把创建Shape类做成抽象类,并提供一个抽象方法draw,让子类去实现。当有新功能增加时只需要让新的图形类去继承Shape,并且实现draw方法,那么适用方GraphicEditor类就不用修改代码了,里面直接调用draw方法就行了。
package cn.zhku.improve;
public class Ocp {
public static void main(String[] args) {
//使用看看存在的问题
GraphicEditor graphicEditor = new GraphicEditor();
graphicEditor.drawShape(new Rectangle());
graphicEditor.drawShape(new Circle());
graphicEditor.drawShape(new Triangle());
graphicEditor.drawShape(new Other());
}
}
//这是一个用于绘图的类 [使用方]
class GraphicEditor {
//接收Shape对象,然后根据type,来绘制不同的图形
public void drawShape(Shape s) {
s.draw();
}
}
//Shape类,基类
abstract class Shape {
int m_type;
public abstract void draw();//抽象方法
}
class Rectangle extends Shape {
Rectangle() {
super.m_type = 1;
}
@Override
public void draw() {
System.out.println("绘制矩形");
}
}
class Circle extends Shape {
Circle() {
super.m_type = 2;
}
@Override
public void draw() {
System.out.println("绘制圆形");
}
}
//新增画三角形
class Triangle extends Shape {
Triangle() {
super.m_type = 3;
}
@Override
public void draw() {
System.out.println("绘制三角形");
}
}
//新增图形
class Other extends Shape{
Other(){
super.m_type = 4;
}
@Override
public void draw() {
System.out.println("绘制其他图形");
}
}
理解:最少知道原则,即一个类对自己依赖的类知道的越少越好,也就是说对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部,对外除了提供的public方法,不对外泄露任何信息。
直接朋友:每个对象都会与其他对象有耦合关系,只是两个对象之间有耦合关系,其中我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友。
案例:
import java.util.ArrayList;
import java.util.List;
//客户端
public class Demeter1 {
public static void main(String[] args) {
//创建了一个 SchoolManager 对象
SchoolManager schoolManager = new SchoolManager();
//输出学院的员工id 和 学校总部的员工信息
schoolManager.printAllEmployee(new CollegeManager());
}
}
//学校总部员工类
class Employee {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
//学院的员工类
class CollegeEmployee {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
//管理学院员工的管理类
class CollegeManager {
//返回学院的所有员工
public List<CollegeEmployee> getAllEmployee() {
List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
CollegeEmployee emp = new CollegeEmployee();
emp.setId("学院员工id= " + i);
list.add(emp);
}
return list;
}
}
//学校管理类
//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则
class SchoolManager {
//返回学校总部的员工
public List<Employee> getAllEmployee() {
List<Employee> list = new ArrayList<Employee>();
for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
Employee emp = new Employee();
emp.setId("学校总部员工id= " + i);
list.add(emp);
}
return list;
}
//该方法完成输出学校总部和学院员工信息(id)
void printAllEmployee(CollegeManager sub) {
//分析问题
//1. 这里的 CollegeEmployee 不是 SchoolManager的直接朋友
//2. CollegeEmployee 是以局部变量方式出现在 SchoolManager
//3. 违反了 迪米特法则
//获取到学院员工
List<CollegeEmployee> list1 = sub.getAllEmployee();
System.out.println("------------学院员工------------");
for (CollegeEmployee e : list1) {
System.out.println(e.getId());
}
//获取到学校总部员工
List<Employee> list2 = this.getAllEmployee();
System.out.println("------------学校总部员工------------");
for (Employee e : list2) {
System.out.println(e.getId());
}
}
}
解决:
import java.util.ArrayList;
import java.util.List;
//客户端
public class Demeter1 {
public static void main(String[] args) {
System.out.println("~~~使用迪米特法则的改进~~~");
//创建了一个 SchoolManager 对象
SchoolManager schoolManager = new SchoolManager();
//输出学院的员工id 和 学校总部的员工信息
schoolManager.printAllEmployee(new CollegeManager());
}
}
//学校总部员工类
class Employee {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
//学院的员工类
class CollegeEmployee {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
//管理学院员工的管理类
class CollegeManager {
//返回学院的所有员工
public List<CollegeEmployee> getAllEmployee() {
List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
CollegeEmployee emp = new CollegeEmployee();
emp.setId("学院员工id= " + i);
list.add(emp);
}
return list;
}
//输出学院员工的信息
public void printEmployee() {
//获取到学院员工
List<CollegeEmployee> list1 = getAllEmployee();
System.out.println("------------学院员工------------");
for (CollegeEmployee e : list1) {
System.out.println(e.getId());
}
}
}
//学校管理类
//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则
class SchoolManager {
//返回学校总部的员工
public List<Employee> getAllEmployee() {
List<Employee> list = new ArrayList<Employee>();
for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
Employee emp = new Employee();
emp.setId("学校总部员工id= " + i);
list.add(emp);
}
return list;
}
//该方法完成输出学校总部和学院员工信息(id)
void printAllEmployee(CollegeManager sub) {
//分析问题
//1. 将输出学院的员工方法,封装到CollegeManager
sub.printEmployee();
//获取到学校总部员工
List<Employee> list2 = this.getAllEmployee();
System.out.println("------------学校总部员工------------");
for (Employee e : list2) {
System.out.println(e.getId());
}
}
}
理解:尽量使用合成/聚合的方式,而不是使用继承。
创建者模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
行为型模式:模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式(责任链模式)
步骤:
代码:
package type1;
public class SingletonTest1 {
public static void main(String[] args) {
//测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次创建的对象是否相同:"+(instance1==instance2));
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
//饿汉式(静态变量)
class Singleton{
//1、构造器私有化
private Singleton(){
}
//2、在本类内部创建对象实例
private final static Singleton instance = new Singleton();
//3、对外提供一个公有的静态方法
public static Singleton getInstance(){
return instance;
}
}
优点:写法比较简单,在类装载的时候完成了实例化,避免了线程同步的问题。
缺点:在类装载的时候就完成实例化,没有打到懒加载的效果,如果从始至终都没有使用过这个实力,则会造成内存的浪费。
结论:这种单例模式可用,可能造成内存浪费
代码:
package type2;
public class SingletonTest2 {
public static void main(String[] args) {
//测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次创建的对象是否相同:"+(instance1==instance2));
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
//饿汉式(静态变量)
class Singleton{
//1、构造器私有化
private Singleton(){
}
//2、在本类内部创建对象实例
private static Singleton instance;
static {//在静态代码块中,创建单例对象
instance = new Singleton();
}
//3、对外提供一个公有的静态方法
public static Singleton getInstance(){
return instance;
}
}
步骤:
构造器私有化
定义一个类成员变量
提供一个静态的公有方法,当使用到该方法的时候才去创建instance对象
代码:
package type3;
public class SingletonTest3 {
public static void main(String[] args) {
System.out.println("懒汉式(线程不安全)");
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次创建的对象是否相同:"+(instance1==instance2));
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
private static Singleton instance;
private Singleton(){
}
//提供一个静态的公有方法,当使用到该方法时,才去创建instance
//懒汉式,在使用的时候才开始创建对象
public static Singleton getInstance(){
//判断有没有对象,如果没有就创建,有则返回
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
优缺点:
步骤:在上一种的方式中对方法加入了同步代码块。
//提供一个静态的公有方法,加入了同步处理代码synchronized
//懒汉式,在使用的时候才开始创建对象
public static synchronized Singleton getInstance(){
//判断有没有对象,如果没有就创建,有则返回
if (instance == null){
instance = new Singleton();
}
return instance;
}
优缺点:
代码:
public static Singleton getInstance(){
//判断有没有对象,如果没有就创建,有则返回
if (instance == null){
synchronized (Singleton.class){
instance = new Singleton();
}
}
return instance;
}
代码:
package type6;
public class SingletonTest6 {
public static void main(String[] args) {
System.out.println("双重检查");
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次创建的对象是否相同:"+(instance1==instance2));
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
//双重检查
class Singleton{
//加volatile关键字
private static volatile Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
//提供一个公有的静态方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题
//同时保证了效率,推荐使用这种方式
if (instance == null){
synchronized ((Singleton.class)){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
优缺点:
代码:
package type7;
public class SingletonTest7 {
public static void main(String[] args) {
System.out.println("静态内部类实现单例模式");
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次创建的对象是否相同:"+(instance1==instance2));
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
//静态内部类实现单例模式,推荐使用
class Singleton{
//加volatile关键字
private static volatile Singleton instance;
private Singleton(){
}
//静态内部类一开始不会被实例化
//写一个静态内部类,该类中有一个静态的属性,该类在一开始Singleton类被装载时并不会被立即实例化
private static class SingleInstance{
private static final Singleton INSTANCE = new Singleton();
}
//提供一个静态的公有方法,直接返回SingleInstance.INSTANCE
public static synchronized Singleton getInstance(){
//返回SingleInstance静态内部类,而静态内部类在装载的时候是线程安全的
return SingleInstance.INSTANCE;
}
}
优缺点:
代码:
package type8;
public class SingletonTest8 {
public static void main(String[] args) {
SingleTon singleTon1 = SingleTon.INSTANCE;
SingleTon singleTon2 = SingleTon.INSTANCE;
System.out.println(singleTon1==singleTon2);
System.out.println(singleTon1.hashCode());
System.out.println(singleTon2.hashCode());
}
}
//使用枚举可以实现单例,推荐使用
enum SingleTon{
INSTANCE;//属性
public void sayOK(){
System.out.println("OK");
}
}
优缺点:
在JDK中,java.lang.Runtime就是经典的单例模式(饿汉式)
理解:
案例:
抽象类Pizza类
//将Pizza类做成抽象
public abstract class Pizza {
protected String name; //名字
//准备原材料, 不同的披萨不一样,因此,我们做成抽象方法
public abstract void prepare();
public void bake() {
System.out.println(name + " baking;");
}
public void cut() {
System.out.println(name + " cutting;");
}
//打包
public void box() {
System.out.println(name + " boxing;");
}
public void setName(String name) {
this.name = name;
}
}
三个Pizza类的子类
public class CheesePizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println(" 给制作奶酪披萨 准备原材料 ");
}
}
public class GreekPizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println(" 给希腊披萨 准备原材料 ");
}
}
public class PepperPizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println(" 给胡椒披萨准备原材料 ");
}
}
模拟去披萨店买pizza的场景,客户需要告知店家要哪种pizza,然后店家开始按步骤制作。
店家代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import simplefactory.pizza.Pizza;
public class OrderPizza2 {
Pizza pizza = null;
String orderType = "";//pizza类型
// 构造器
public OrderPizza2() {
do {
orderType = getType();
pizza = SimpleFactory.createPizza2(orderType);
// 输出pizza
if (pizza != null) { // 订购成功
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println(" 订购披萨失败 ");
break;
}
} while (true);
}
// 写一个方法,可以获取客户希望订购的披萨种类
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
而店家是把客户需要的pizza类型传给工厂,然后就得到一个pizza对象,再进行制作。这里的工厂类起到的作用是给店家传一个pizza的对象,它根据客户的要求去帮店家new一个pizza对象出来。
工厂代码:
import simplefactory.pizza.CheesePizza;
import simplefactory.pizza.GreekPizza;
import simplefactory.pizza.PepperPizza;
import simplefactory.pizza.Pizza;
//简单工厂类
public class SimpleFactory {
//简单工厂模式 也叫 静态工厂模式
public static Pizza createPizza2(String orderType) {
Pizza pizza = null;
System.out.println("使用简单工厂模式2");
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(" 希腊披萨 ");
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName(" 奶酪披萨 ");
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName("胡椒披萨");
}
return pizza;
}
}
理解:
案例::客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒pizza 或者是伦敦的奶酪pizza、伦敦的胡椒pizza。
代码:
//将Pizza类做成抽象
public abstract class Pizza {
protected String name; //名字
//准备原材料, 不同的披萨不一样,因此,我们做成抽象方法
public abstract void prepare();
public void bake() {
System.out.println(name + " baking;");
}
public void cut() {
System.out.println(name + " cutting;");
}
//打包
public void box() {
System.out.println(name + " boxing;");
}
public void setName(String name) {
this.name = name;
}
}
public class BJCheesePizza extends Pizza{
@Override
public void prepare() {
setName("北京奶酪pizza");
System.out.println("北京的奶酪pizza准备原料");
}
}
public class BJPepperPizza extends Pizza{
@Override
public void prepare() {
setName("北京胡椒pizza");
System.out.println("北京的胡椒pizza准备原料");
}
}
public class LDCheesePizza extends Pizza{
@Override
public void prepare() {
setName("伦敦奶酪pizza");
System.out.println("伦敦的奶酪pizza准备原料");
}
}
public class LDPepperPizza extends Pizza{
@Override
public void prepare() {
setName("伦敦胡椒pizza");
System.out.println("伦敦的胡椒pizza准备原料");
}
}
店家类定义一个抽象方法createPizza,让工厂子类去实现
public abstract class OrderPizza {
//定义一个抽象方法,createPizza , 让各个工厂子类自己实现
abstract Pizza createPizza(String orderType);
// 构造器
public OrderPizza() {
Pizza pizza = null;
String orderType; // 订购披萨的类型
do {
orderType = getType();
pizza = createPizza(orderType); //抽象方法,由工厂子类完成
//输出pizza 制作过程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
// 写一个方法,可以获取客户希望订购的披萨种类
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
public class BJOrderPizza extends OrderPizza{
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("cheese")){
pizza = new BJCheesePizza();
}else if (orderType.equals("pepper")){
pizza = new BJPepperPizza();
}
return pizza;
}
}
public class LDOrderPizza extends OrderPizza{
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("cheess")){
pizza = new LDCheesePizza();
}else if (orderType.equals("pepper")){
pizza = new LDPepperPizza();
}
return pizza;
}
}
理解:
抽象工厂接口代码:
//一个抽象工厂模式的抽象层(接口)
public interface AbstractFactory {
//让下面的工厂子类去具体实现
public Pizza createPizza(String orderType);
}
具体的工厂类:
public class BJFactory implements AbstractFactory{
@Override
public Pizza createPizza(String orderType) {
System.out.println("使用的是抽象工厂模式");
Pizza pizza = null;
if (orderType.equals("pepper")){
pizza = new BJPepperPizza();
}else if (orderType.equals("cheese")){
pizza = new BJCheesePizza();
}
return pizza;
}
}
public class LDFactory implements AbstractFactory{
@Override
public Pizza createPizza(String orderType) {
System.out.println("使用的是抽象工厂模式");
Pizza pizza = null;
if (orderType.equals("pepper")){
pizza = new LDPepperPizza();
}else if (orderType.equals("cheese")){
pizza = new LDCheesePizza();
}
return pizza;
}
}
订购制作:
public class OrderPizza {
AbstractFactory factory;
//构造器,在调用的时候需要指明要用哪一家工厂(抽象工厂的实现类)
public OrderPizza(AbstractFactory abstractFactory){
setAbstractFactory(abstractFactory);
}
public void setAbstractFactory(AbstractFactory factory){
Pizza pizza = null;
String orderType = "";//用户输入
this.factory = factory;
do {
orderType = getType();
//factory可能是BJ工厂子类,也可以是LD工厂子类
pizza = factory.createPizza(orderType);
if (pizza!=null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("订购失败");
break;
}
}while (true);
}
// 写一个方法,可以获取客户希望订购的披萨种类
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
在Calendar类中应用了简单工厂模式