文章目录
设计模式:对特定问题的解决方案
单例模式
解决问题
一个类只能创建一个实例,例如MyApplication、SocketConnection
解决方案
private构造方法,static newInstance()返回类本身
普通程序
在Eclipse中新建一个MyApplication.java
public class MyApplication {
public MyApplication(){
System.out.println(this.toString()+"构造方法");
}
}
Main.java
public class Main {
public static void main(String[] args){
for(int i=0;i<10;i++){
MyApplication application = new MyApplication();
}
}
}
查看输出,可以看到新建了10个MyApplication对象
MyApplication@15db9742构造方法
MyApplication@6d06d69c构造方法
......
MyApplication@42a57993构造方法
改为单例模式
MyApplication.java
public class MyApplication {
private static MyApplication instance;
public static MyApplication newInstance(){
if(instance == null){
instance = new MyApplication();
}
return instance;
}
private MyApplication(){
System.out.println(this.toString()+"构造方法");
}
}
Main.java
public class Main {
public static void main(String[] args){
for(int i=0;i<10;i++){
MyApplication application = MyApplication.newInstance();
}
}
}
运行,查看输出,可以看到只创建了一个MyApplication对象
MyApplication@15db9742构造方法
做些不同尝试:
Main.java中的程序改为
public class Main {
public static void main(String[] args){
new Thread(){
public void run(){
for(int i=0;i<10;i++){
MyApplication application = MyApplication.newInstance();
}
}
}.start();
}
}
查看输出
MyApplication@6426ac69构造方法
Main.java改为
public class Main {
public static void main(String[] args){
for(int i=0;i<10;i++){
new Thread(){
public void run(){
MyApplication application = MyApplication.newInstance();
}
}.start();
}
}
}
查看输出,不一定次数的构造方法
tarena.day0101.MyApplication@381037cd构造方法
tarena.day0101.MyApplication@10b7ce35构造方法
tarena.day0101.MyApplication@5895a81c构造方法
tarena.day0101.MyApplication@4a8f0963构造方法
tarena.day0101.MyApplication@44ea4bd2构造方法
tarena.day0101.MyApplication@407e3dad构造方法
为什么不是一个构造方法呢?怎样保证多个线程也创建一个MyApplication呢?改为
public class MyApplication {
private static MyApplication instance;
//synchronized前面的线程执行完,后边的线程才会执行
//不加,就是多个线程同时执行这个方法
public synchronized static MyApplication newInstance(){
if(instance == null){
instance = new MyApplication();
}
return instance;
}
private MyApplication(){
System.out.println(this.toString()+"构造方法");
}
}
再次运行,查看输出
MyApplication@6426ac69构造方法
工厂设计模式
解决问题
创建对象时,解耦合
解决方案
使用对象的地方调工厂返回的接口
普通程序
public class LoginByUserBiz {
public boolean login(Object object){
System.out.println("LoginByUserBiz-login()");
return true;
}
}
public class LoginView {
public static void main(String[] args){
//直接创建对象,耦合高,一个地方改,其他地方都要改
LoginByUserBiz biz = new LoginByUserBiz();
biz.login(null);
}
}
查看输出
LoginByUserBiz-login()
改为工厂设计模式
创建ILoginBiz
public interface ILoginBiz {
public boolean login(Object object);
}
创建LoginBySmsBiz并实现这个接口
public class LoginBySmsBiz implements ILoginBiz{
public boolean login(Object object){
System.out.println("LoginBySmsBiz-login()");
return true;
}
}
刚才的LoginByUserBiz也实现这个接口
public class LoginByUserBiz implements ILoginBiz{
public boolean login(Object object){
System.out.println("LoginByUserBiz-login()");
return true;
}
}
现在创建工厂Factory
public class Factory {
public static ILoginBiz Instance(){
return new LoginByUserBiz();
}
}
LoginView
public class LoginView {
public static void main(String[] args){
//调接口,解耦合,耦合低
ILoginBiz iLoginBiz = Factory.newInstance();
iLoginBiz.login(null);
}
}
查看输出
LoginByUserBiz-login()
如果现在需要换sms登录,那么我们只需要修改Factory
public class Factory {
public static ILoginBiz newInstance(){
//return new LoginByUserBiz();
return new LoginBySmsBiz();
}
}
查看输出
LoginBySmsBiz-login()
观察者设计模式
解决问题
下一层Biz层的数据发生变化,上一层View层要知道
解决方案
目标(下一层Biz层)发生变化,调观察者(接口)
观察者设计模式程序
创建接口Observer
//定义每个观察者要实现的功能
public interface Observer {
public String save();
}
创建三个观察者,都实现Observer接口
public class Wukong implements Observer {
@Override
public String save() {
return "Wukong来了";
}
}
public class Bajie implements Observer {
@Override
public String save() {
return "Bajie来了";
}
}
public class Shaseng implements Observer {
@Override
public String save() {
return "Shaseng来了";
}
}
创建目标
//目标
public class Tangseng {
ArrayList<Observer> observerArrayList = new ArrayList<>();
public void register(Observer observer){
observerArrayList.add(observer);
}
//目标发生变化,调用观察者
public ArrayList<String> help(){
ArrayList<String> stringArrayList = new ArrayList<>();
for(Observer observer:observerArrayList){
String string = observer.save();
stringArrayList.add(string);
}
return stringArrayList;
}
}
创建界面,点击按钮需要展示通知三个徒弟
MainActivity
public class MainActivity extends AppCompatActivity {
private Button button;
private ListView listView;
//目标
Tangseng tangseng;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建三个观察者
Wukong wukong = new Wukong();
Bajie bajie = new Bajie();
Shaseng shaseng = new Shaseng();
tangseng = new Tangseng();
tangseng.register(wukong);
tangseng.register(bajie);
tangseng.register(shaseng);
button = findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
test();
}
});
listView = findViewById(R.id.listView);
}
private void test() {
ArrayList<String> arrayList = tangseng.help();
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_expandable_list_item_1, arrayList);
listView.setAdapter(arrayAdapter);
}
}
装饰模式
概念
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
特点
(1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
(2) 装饰对象包含一个真实对象的引用(reference)
(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
适用条件
以下情况使用Decorator模式
(1)需要扩展一个类的功能,或给一个类添加附加职责。
(2)需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
(3)需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
(4)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
优点
(1)Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
(2)通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
缺点
(1)这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
(2)装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
代码中的应用
IO流的操作就是典型的装饰模式
举个栗子
创建装饰模式公共接口IPerson
/**
* 装饰模式公共接口
*/
public interface IPerson {
void desc();
}
创建被装饰类 Errol
/**
* 被装饰类
*/
public class Errol implements IPerson{
@Override
public void desc() {
Log.d("TTT","Errol是一个人");
}
}
创建装饰器,通过装饰器来装饰 Errol。装饰器和被装饰类要实现同一个公共接口,同时装饰器中需要持有被装饰类,被装饰类以公共接口的方式接收,这样的好处是可以通过不同的装饰组合出现不同的对象
/**
* 装饰器
*/
public class PersonDecorator implements IPerson{
/**
* 持有被装饰类,以公共接口接收
*/
IPerson iPerson;
public PersonDecorator(IPerson iPerson){
this.iPerson = iPerson;
}
@Override
public void desc() {
iPerson.desc();
}
}
现在需要创建不同的装饰子类,真正的装饰内容在装饰子类中实现
/**
* 装饰子类
*/
public class SmartPerson extends PersonDecorator {
public SmartPerson(IPerson iPerson) {
super(iPerson);
}
@Override
public void desc() {
super.desc();
Log.d("TTT","是一个聪明的人");
}
}
测试一下
IPerson iPerson = new Errol();
iPerson.desc();
iPerson = new SmartPerson(new Errol());
iPerson.desc();
D/TTT: Errol是一个人
D/TTT: Errol是一个人
D/TTT: 是一个聪明的人