第十四章 设计模式
1.作业回顾
//1,将Frock(连衣裙)类声明为抽象类,尺寸在Frock类中定义,
//在类中声明抽象方法calcArea方法,用来计算衣服的布料面积。
//编写Shirt类继承Frock类,实现 calcArea方法,用来计算衬衣所需的布料面积(尺寸 * 1.3)。
//编写Coat类继承Frock类,实现 calcArea方法,用来计算外套所需的布料面积(尺寸*1.5)。
public abstract class Frock{
protected double size;
public Frock(double size) {
super();
this.size = size;
}
public double getSize() {
return size;
}
public void setSize(double size) {
this.size = size;
}
public abstract double calcArea();
}
class Shirt extends Frock{
public Shirt(double size) {
super(size);
}
public double calcArea() {
return size * 1.3;
}
}
class Coat extends Frock{
public Coat(double size) {
super(size);
}
public double calcArea() {
return size * 1.5;
}
}
public class Day13HomeWork {
// 编写Test类,测试calcArea方法。
public static void main(String[] args) {
Shirt s = new Shirt(180);
System.out.println(s.calcArea());//234.0
Coat c = new Coat(180);
System.out.println(c.calcArea());//270.0
}
}
2.内部类
可以将一个类的定义放在另一个类的内部,这叫做内部类。
//Foo是一个外部类
public class Foo {
//bar是一个内部类
public class bar{
}
}
内部类可以访问外部类的属性。(尚未理解)
//从内部类bar中访问外部类Foo的数据v1
public class Foo {
private int v1;
public Foo(int v1) {
super();
this.v1 = v1;
}
public void fooF() {
//创建内部类的对象,编译器会将this传递给Bar的构造器
//这样内部类的对象就持有外部类对象的引用
Bar bar = new Bar();
bar.barF();
}
//bar是一个内部类
public class Bar{
public void barF(){
//内部类访问外部类的属性
//内部类的对象有一个对外部类的对象的引用outer,因此可以访问外部类的数据
//outer无视访问修饰符
//outer不是java关键字
System.out.println(v1);
}
}
public static void main(String[] args) {
Foo foo = new Foo(10);
foo.fooF();//10
//创建内部类的对象必须先有外部类的对象
//使用foo. new Bar(),编译器会将foo作为参数传递给Bar的构造器
Bar bar = foo.new Bar();
bar.barF();//10
//bar和 bar2持有同一个外部类对象的引用
Foo.Bar bar2 = foo.new Bar();
bar2.barF();//10
}
}
2.1局部内部类
局部内部类就是在方法中声明的内部类,它可以使内部类无法被外界察觉。
//从内部类bar中访问外部类Foo的数据v1
public class Foo {
private int v1;
public Foo(int v1) {
super();
this.v1 = v1;
}
public void fooF() {
//bar是一个局部内部类
class Bar{
public void barF(){
//内部类访问外部类的属性
//内部类的对象有一个对外部类的对象的引用outer,因此可以访问外部类的数据
//outer无视访问修饰符
//outer不是java关键字
System.out.println(v1);
}
}
//创建内部类的对象,编译器会将this传递给Bar的构造器
//这样内部类的对象就持有外部类对象的引用
Bar bar = new Bar();
bar.barF();
}
public static void main(String[] args) {
Foo foo = new Foo(10);
foo.fooF();//10
}
}
2.2静态内部类
有时候使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外部类的对象。这种情况可以使用静态内部类。
//从内部类bar中访问外部类Foo的数据v1
public class Foo {
private int v1;
public Foo(int v1) {
super();
this.v1 = v1;
}
public void fooF() {
//创建内部类的对象,编译器会将this传递给Bar的构造器
//这样内部类的对象就持有外部类对象的引用
Bar bar = new Bar();
bar.barF();
}
//bar是一个静态内部类
static class Bar{
public void barF(){
// System.out.println(v1);//编译错误,没有外部引用
}
}
public static void main(String[] args) {
Foo foo = new Foo(10);
foo.fooF();
//尚未理解
Foo.Bar bar = new Foo.Bar();
bar.barF();
}
}
2.3匿名内部类
没有名字的内部类叫做匿名内部类。
interface Flyable {
void fly();
}
class FlyableImple implements Flyable{
public void fly() {
System.out.println("飞1");
}
}
public class Day1402 {
public static void main(String[] args) {
//需要一个实现了Flyable接口的对象
Flyable f1 = new FlyableImple();
f1.fly();//飞1
//如果这个对象只需要一个,那么创建一个类去实现接口就太麻烦了
//使用匿名内部类可以解决这个问题
//Flyable后面的大括号中间的内容就是一个匿名内部类
Flyable f2 = new Flyable() {
public void fly() {
System.out.println("飞2");
}
};
f2.fly();//飞2
Flyable f3 = new Flyable() {
public void fly() {
System.out.println("飞3");
}
};
f3.fly();//飞3
}
}
3.设计模式
3.1单例模式
在软件运行过程中会创建很多对象,有些对象的创建非常消耗资源,并且只需要一个。这种情况可以使用单例模式。
注:尚未理解
public class SingletonDemo {
//当类加载时创建一个实例
//由于类只会加载一次,所以能保证创建唯一的对象
private static SingletonDemo instance = new SingletonDemo();
//构造器为private,外部无法调用此构造器
private SingletonDemo() {
}
public static SingletonDemo getInstance() {
return instance;
}
}
import 内部类.Foo;
public class Day1403 {
public static void main(String[] args) {
//控制不了创建多少个对象
Foo f1 = new Foo(0);
Foo f2 = new Foo(0);
SingletonDemo s1 = SingletonDemo.getInstance();
SingletonDemo s2 = SingletonDemo.getInstance();
System.out.println(s1 == s2);//true
}
}
3.2代理模式
代理模式可以在不改变源代码的情况下对目标对象进行访问控制和功能扩展。
目标对象(RealSubject)是完成实际功能的对象。
代理对象(Proxy)是目标对象的替身,用户与RealSubject的交互必须通过Proxy。
例如:去4s店保养。客户经理是代理对象,技术工人是目标对象。 客户先和客户经理交互,确认保养内容。然后客户经理会将保养车辆的工作交给技术工人完成。当实际工作完成后,客户需要和客户经理确认并付款。
1,代理对象完成前置工作 2,目标对象完成实际工作 3,代理对象完成后置工作。
//接口描述了对外提供的功能
public interface Subject {
//代理对象对外宣传的功能
void work();
}
public class RealSubject implements Subject {
//实际工作
public void work() {
System.out.println("拍摄广告");
}
}
//代理对象,将实际工作委托给目标对象的引用
public class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject) {
super();
this.subject = subject;
}
public void work() {
//前置工作
System.out.println("谈合同");
//将实际工作委托给目标对象完成
subject.work();
//后置工作
System.out.println("付款问题");
}
}
public class Day1404 {
public static void main(String[] args) {
//创建目标对象
RealSubject realsbuject = new RealSubject();
//创建代理对象
Proxy proxy = new Proxy(realsbuject);
//代理完成工作
proxy.work();
}
}
Proxy和RealSubject都实现了Subject接口,这允许任何客户都可以像处理RealSubject对象一样处理Proxy对象。
客户与RealSubject的交互都必须通过Proxy。任何用到RealSubject的地方,都可以用Proxy取代。 RealSubject是真正做事的对象,proxy会控制对RealSubject的访问。 Proxy持有对RealSubject的引用。所以必要时它可以将请求转发给RealSubject。
3.3观察者模式
观察者模式其实就是发布订阅模式,发布者发布消息后,订阅者就可以得到消息通知。
观察者模式设计发布者。 抽象的观察者。 具体的观察者。
例如:有一个气象站,多个观察者订阅天气预报,气象站会向已订阅的观察者推送天气预报。
//天气预报的数据
public class WeatherData {
// 温度
private int temperature;
// 风力
private int windPower;
public WeatherData(int temperature, int windPower) {
super();
this.temperature = temperature;
this.windPower = windPower;
}
public int getTemperature() {
return temperature;
}
public void setTemperature(int temperature) {
this.temperature = temperature;
}
public int getWindPower() {
return windPower;
}
public void setWindPower(int windPower) {
this.windPower = windPower;
}
}
//一个接口,抽象的观察者
//所有实现该接口的类的对象都是观察者
public interface WeatherObserver {
// 观察者接收气象台发布的数据
void update(WeatherData data);
}
class RealObserver implements WeatherObserver {
//观察者的名字
private String name;
public RealObserver(String name) {
this.name = name;
}
//当气象数据传递进来以后,在控制台输出气象数据
public void update(WeatherData data) {
System.out.println(name + "收到天气数据");
System.out.println("温度:" + data.getTemperature());
System.out.println("风力:" + data.getWindPower());
}
}
//气象站
public class WeatherStation {
//定义一个数组来保存注册的观察者
private WeatherObserver[] observers = new WeatherObserver[10];
//已注册的观察者的数量
private int count = 0;
//注册观察者
public void register(WeatherObserver observer) {
if(count >= 10){
System.out.println("注册失败");
}else{
//将观察者保存到数组中
observers[count] = observer;
count++;
}
}
//发布数据,通知观察者
public void notifyObserver(WeatherData data){
//逐个通知观察者
for (int i = 0; i < count; i++) {
//调用观察者的update方法,传递天气数据
observers[i].update(data);
}
}
}
public class Day1405 {
public static void main(String[] args) {
WeatherStation ws = new WeatherStation();
WeatherObserver o1 = new RealObserver("观察者1");
WeatherObserver o2 = new RealObserver("观察者2");
WeatherObserver o3 = new RealObserver("观察者3");
WeatherObserver o4 = new RealObserver("观察者4");
WeatherObserver o5 = new RealObserver("观察者5");
ws.register(o1);
ws.register(o2);
ws.register(o3);
ws.register(o4);
ws.register(o5);
WeatherData data = new WeatherData(20, 2);
ws.notifyObserver(data);
}
}
3.4模板模式
//银行业务模板
public abstract class BankBusinessTemplate {
//取号
protected long takeNumber() {
//1000以内的随机数
int r = (int) (Math.random() * 1000);
return r;
}
//具体的业务,声明为抽象方法,交给子类来实现
protected abstract String doAction(long number);
//保存客户反馈
protected void saveEvaluation(long number, String evaluation) {
System.out.println("号码:" + number + "的评价:" + evaluation);
}
//业务流程
public void business() {
//1
long number = takeNumber();
//2
String evaluation = doAction(number);
//3
saveEvaluation(number, evaluation);
}
}
//开卡业务
public class NewCard extends BankBusinessTemplate {
//办理具体的业务
protected String doAction(long number) {
System.out.println("办理开卡业务");
return "五星好评";
}
}
//挂失业务
public class LossCard extends BankBusinessTemplate {
//办理具体的业务
protected String doAction(long number) {
System.out.println("办理挂失业务");
return "五星好评";
}
}
public class Day1406 {
public static void main(String[] args) {
NewCard newCard = new NewCard();
newCard.business();
LossCard lossCard = new LossCard();
lossCard.business();
}
}
4.练习
编写一个比较器AreaComparator比较实现了Areable接口的任意图形的面积,Circle,Triangel,Rectangle等等。编写一个测试类AreaComparatorTest来测试任意图形面积的比较结果。