2015-09-16 2 views
1

Я новичок в Android и MVP в целом, и я занимаюсь программированием на iOS в течение последних 1,5 лет, поэтому считаю, что шаблоны делегатов легко усваиваются. Я реализовал MVP таким образом, чтобы представление соответствовало протоколу ведущего, что позволяет ведущему игнорировать конкретный тип представления, но позволяет ему знать, что определенные методы являются заданными и, таким образом, могут вызвать «представление». Я читал различные руководства MVP и все учебники по Мосби, и я не уверен, что согласен с некоторыми из них. Является ли шаблон, который я реализовал кошерным? Я хотел бы некоторую обратную связь, так что я не держать движется в плохом направлении, если это действительно то, что я делаю ...Является ли мой шаблон реализации для MVP действительным?

Например,

База Presenter:

public abstract class Presenter<V, S> implements BasePresenterInterface<V, S> { 

    public interface PresenterProtocol extends BasePresenterProtocol { 

    } 

    private WeakReference<V> mAttachedView = null; 
    private S mService = null; 

    /** 
    * Interface Overrides 
    */ 
    @Override 
    public void attachView(V view) { 
     boolean viewDoesNotConform = !viewDoesConform(view); 
     if (viewDoesNotConform) { 
      Log.d("DEBUG", "Cannot attach View that does not conform to PresenterProtocol"); 
      return; 
     } 

     mAttachedView = new WeakReference<>(view); 
     ((BasePresenterProtocol) getAttachedView()).onViewAttached(); 
    } 

    @Override 
    public void detachView() { 
     mAttachedView = null; 
    } 

    @Override 
    public boolean viewDoesConform(V view) { 
     Class<?> klass = view.getClass(); 
     boolean conforms = BasePresenterInterface.BasePresenterProtocol.class.isAssignableFrom(klass); 

     return conforms; 
    } 

    @Override 
    public boolean viewIsAttached() { 
     return mAttachedView != null; 
    } 

    @Override 
    public V getAttachedView() { 
     return mAttachedView.get(); 
    } 

    @Override 
    public S getService() { 
     return mService; 
    } 

    @Override 
    public void setService(S service) { 
     mService = service; 
    } 
} 

Я тогда подклассы это в следующем:

PhotoRecyclerPresenter:

public class PhotoRecyclerPresenter extends Presenter<PhotoRecyclerPresenter.PhotoRecyclerPresenterProtocol, PhotoService> { 
    public interface PhotoRecyclerPresenterProtocol extends Presenter.PresenterProtocol { 
     void onPhotosLoaded(List<TestPhoto> photoList); 
     void onItemSelected(TestPhoto photo); 
     void onShowDetail(TestPhoto photo); 
    } 

    private static PhotoRecyclerPresenter mSharedInstance; 

    private PhotoRecyclerPresenter() { 
     setService(new PhotoService()); 
    } 

    /** 
    * External Methods 
    */ 

    public void getPhotos() { 
     boolean noAttachedView = !viewIsAttached(); 
     if (noAttachedView) { 
      Log.d("DEBUG", "No view attached"); 
      return; 
     } 

     getService().getAPI() 
        .getPhotos() 
        .observeOn(AndroidSchedulers.mainThread()) 
        .subscribe(photoList -> getAttachedView().onPhotosLoaded(photoList)); 
    } 


    /** 
    * Internal Methods 
    */ 

    public static PhotoRecyclerPresenter getSharedInstance() { 
     boolean firstInstance = mSharedInstance == null; 
     if (firstInstance) { 
      setSharedInstance(new PhotoRecyclerPresenter()); 
     } 

     return mSharedInstance; 
    } 

    public static void setSharedInstance(PhotoRecyclerPresenter instance) { 
     mSharedInstance = instance; 
    } 

    public void didSelectItem(TestPhoto photo) { 
     getAttachedView().showDetail(photo); 
    } 
} 

И он общается с целью: PhotoRecyclerFragment:

public class PhotoRecyclerFragment extends Fragment implements PhotoRecyclerPresenter.PhotoRecyclerPresenterProtocol { 

    private RecyclerView    mRecyclerView; 
    private RecyclerView.LayoutManager mLayoutManager; 
    private Activity     mParentActivity; 
    private PhotoRecyclerPresenter  mPresenter; 
    private PhotoRecyclerAdapter mAdapter; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

    } 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View rootView = inflater.inflate(R.layout.fragment_recycler, container, false); 

     mParentActivity = getActivity(); 

     mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView); 
     mLayoutManager = new LinearLayoutManager(mParentActivity); 
     mAdapter = new PhotoRecyclerAdapter(this); 

     mRecyclerView.setLayoutManager(mLayoutManager); 
     mRecyclerView.setAdapter(mAdapter); 

     mPresenter = PhotoRecyclerPresenter.getSharedInstance(); 
     mPresenter.attachView(this); 

     return rootView; 
    } 

    @Override 
    public void onDestroyView() { 
     super.onDestroyView(); 
     mPresenter.detachView(); 
     mAdapter.clear(); 
    } 


    /** 
    * PhotoRecyclerPresenterProtocol Methods 
    */ 


    @Override 
    public void onItemSelected(TestPhoto photo) { 
     mPresenter.didSelectItem(photo); 
    } 

    @Override 
    public void onPhotosLoaded(List<TestPhoto> photoList) { 
     mAdapter.loadPhotos(photoList); 
    } 

    @Override 
    public void onViewAttached() { 
     mPresenter.getPhotos(); 
    } 

    @Override 
    public void onViewDetached() { 

    } 

    @Override 
    public void onShowDetail(TestPhoto photo) { 
     Intent detailIntent = new Intent(mParentActivity, PhotoDetailActivity.class); 
     mParentActivity.startActivity(detailIntent.putExtra(Intent.EXTRA_UID, photo.getPhotoId())); 
    } 
} 

Это позволяет мне определить набор требований, вид должен соответствовать для того, чтобы использовать одноплодную выступающему, сохраняя при этом ведущий агностик о том, какие взгляды используют его, если они соответствуют его протоколу. Пока что в моем практическом проекте это работает нормально, но я не могу найти какие-либо ресурсы, где то, что я делаю, рекомендуется по мере того, как MVP идет, и у меня достаточно сомнений в себе, что я решил, что попрошу мой первый вопрос StackOverflow. Может ли кто-нибудь, кто имеет опыт работы с MVP, пролить свет на это?

Кроме того, если я прошу не в том месте, не стесняйтесь указывать меня в нужное место, чтобы опубликовать это.

Спасибо :)

+1

Я думаю, что его нужно спросить на [code review] (http://codereview.stackexchange.com) – Hamed

+0

, если ваш код полностью работает, вас приветствует Codereview – Caridorc

+0

@Caridorc С дополнительными классами в моем проекте код У меня в отпечатках здесь хорошо работает - мне нужно было бы опубликовать его полностью или просто заставить его работать для себя, чтобы сделать его вопросом обзора кода, а также вопросом «это сломано, помогите мне исправить»? – saganaut

ответ

0

С моей точки зрения, вы делаете то же самое, что делает Мосби. Единственное отличие - это имя интерфейса (или протокола в объективе-с). Вы называете это PresenterProtocol, а Мосби - MvpView. Оба выполняют ту же работу: предлагая Presenter Api методов, которые ведущий может вызвать для управления представлением.

Единственное, что не имеет смысла - это иметь способ viewDoesConform(). В Java у вас есть безопасность типа. Вы можете использовать тип генериков V вашего Presenter, чтобы убедиться, что ваш фрагмент использует протокол Presenter. просто измените его на V extends BasePresentersProtocol

Кроме того, я думаю, что нет смысла иметь «общий экземпляр» (образец a.k.a Singleton) ведущего. Я думаю, что имеет смысл иметь «общий экземпляр» PhotoService. Но, пожалуйста, обратите внимание также, что при этом ваш код не тестируется (модульные тесты). Вам нужно google для инъекции зависимостей или обратного управления, чтобы понять, как писать модульный, многоразовый и проверяемый код. Я не говорю об основах инъекций зависимостей, таких как кинжал, весна или гусь. Вы просто должны понимать идею инъекции зависимостей. Вы можете писать классы, следуя этому принципу, полностью без фреймворков инъекций зависимостей (т. Е. Используя параметры конструктора).

Замечание: вы никогда не отписываете своего докладчика от PhotoService.В зависимости от того, как реализована функция PhotoService, у вас может быть утечка памяти, потому что PhotoService observable имеет ссылку на ведущего, что мешает ведущему и PhotoService (в зависимости от конкретной реализации) от сбора мусора.

Редактировать: Мосби определяет протокол для представления. Взгляните на раздел, посвященный началу работы на веб-сайте проекта. HelloWorldView определяет два метода: showHello() и showGoodbye() (имплантируется HelloWorldActivity) и HelloWorldPresenter вызывает эти два метода для управления представлением. HelloWorldPresenter также отменяет асинхронные запросы, чтобы избежать утечек памяти. Вы тоже должны это сделать. В противном случае ваш ведущий может быть только собранным мусором после завершения модификации httpcall.

+0

Спасибо за отзыв. Я думаю, что Мосби позволяет View определить протокол для ведущего, но я мог бы неправильно понять. Кроме того, служба не является наблюдаемой, а всего лишь экземпляром RestAdapter для Retrofit. Я отвечу на ваш совет и прочитаю о рекомендуемых вами темах. – saganaut

+0

Нет, Мосби определяет протокол для представления. Взгляните на начало раздела на веб-сайте projekt http://hannesdorfmann.com/mosby/ 'HelloWorldView' определяет два метода:' showHello() 'и' showGoodbye() '(имплантированный HelloWorldActivity) и' HelloWorldPresenter' вызывает это два метода управления представлением. HelloWorldPresenter также отменяет асинхронные запросы, чтобы избежать утечек памяти. Вы тоже должны это сделать. В противном случае ваш ведущий может быть собран только после сбора мусора после завершения модификации httpcall. – sockeqwe

+0

Вы абсолютно правы. Я еще раз посмотрел на него, и он делает именно то, что вы сказали, просто названное иначе, чем мое. Это многое разъясняет мне. Спасибо :) – saganaut

Смежные вопросы